简体   繁体   中英

Java streams, create new object based on two different objects

What is the best way to create a new object based on two different objects.

I would like to use java streams.

My two start objects

public class EventA{
    Long id;
    String name;
    ...
    Long locationID;
}

public class EventB{
    Long id
    String Name;
    ...
    Long locationID;
}

And my result class

public class Result{
    Long locationID;
    String eventAName;
    String eventBName;

    public Result(...){...}
}

I have two object arrays like

List<EventA> eventAList;
List<EventB> eventBList;

I like to get an array of Result objects. Every EventA name should be copied to the resultList. If an EventB at the same location exists I would like to save the name in eventBName .

All I have done so far is

List<Result> resultList = eventAList.stream().map(e -> new Result(e.locationID, e.name, null)).collect(Collectors.toList());

I don't know how to pass the value from EventB to the constructor

When creating your Result , you can use a stream to iterate on the values in eventBList to retain only the ones with the same locationID as your eventAList value, then take the value you found, and map() it to it's Name value, or null if it doesn't exists:

List<Result> resultList = eventAList.stream().map(a -> new Result(a.locationID, a.name,
    eventBList.stream().filter(b -> b.locationID.equals(a.locationID)).findAny().map(b -> b.Name).orElse(null)
)).collect(Collectors.toList());

For better performances, you can use a temporary Map :

final Map<Long, String> eventBMap = eventBList.stream().collect(Collectors.toMap(b -> b.locationID, b -> b.Name));

List<Result> resultList = eventAList.stream().map(a -> new Result(a.locationID, a.name,
    eventBMap.get(a.locationID)
)).collect(Collectors.toList());

I found a working way

I adjust the constructor of the Result class to

public Result(Long locationID, String eventAName, EventB eventB){
    this.locationID = locationID;
    this.eventAName = eventAName;
    this.eventBName = eventB.name;
}

and then inside my java stream

List<Result> resultList = eventAList.stream().map(ea -> new Result(ea.locationID, ea.name, eventBList.stream().filter(eb -> eb.locationID.equals(ea.locationID)).findFirst().orElse(new EventB()).get()).collect(Collectors.toList());

You can do something like the following and work on enhancements afterwards (eg create a map for eventBlist by locationId as key in order to have faster search)

Function<EventA, SimpleEntry<EventA, Optional<EventB>>> mapToSimpleEntry = eventA -> new SimpleEntry<>(eventA,
    eventBList.stream()
    .filter(e -> Objects.equals(e.getLocationID(), eventA.getLocationID()))
    .findFirst());

Function<SimpleEntry<EventA, Optional<EventB>>, Result> mapToResult = simpleEntry -> {
    EventA eventA = simpleEntry.getKey();
    Optional<EventB> eventB = simpleEntry.getValue();
    return new Result(eventA.getLocationID(), eventA.getName(), eventB.map(EventB::getName).orElse(null));
};

eventAList.stream()
    .map(mapToSimpleEntry)
    .map(mapToResult)
    .collect(Collectors.toList());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM