Update Objects in One List Based on Values from Second One Using Streams

Update objects in one list based on values from second one using streams

I'd first create a mapping from TimeDiscount::getIdOfBook to TimeDiscount:

Map<Long, TimeDiscount> accumulator = 
actualPromotions.stream()
.collect(toMap(TimeDiscount::getIdOfBook, Function.identity()));

Then I'd do:

booksToReturn.forEach(e -> {
TimeDiscount timeDiscount = accumulator.get(e.getIdOfBook());
if (timeDiscount != null) e.setDiscountRate(e.getDiscountRate() + timeDiscount.getDiscountRate());
});

or if you want to stay with the use of Optional for some reason.

booksToReturn.forEach(e -> 
Optional.ofNullable(accumulator.get(e.getIdOfBook()))
.ifPresent(p -> e.setDiscountRate(e.getDiscountRate() + p.getDiscountRate()))
);

This improves upon the inefficient lookup in actualPromotions.stream() for each element of booksToReturn.

Update one list based on another list using stream

Assuming that you want the currentList item to be replaced by the object from the updatedList the following should work:

currentList.stream().map((p) -> {
return updatedList.stream().filter(u -> p.equals(u)).findFirst().orElse(p);
}).collect(Collectors.toList());

Updating a List of Object from another list of object using java stream

You should not use Stream APIs to change the state of an Object.

If you still want to modify it then,
You can iterate each element from the list of A, filter if dob is null, find dob against the respective name in the list of B.

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

aList.stream()
.filter( a -> a.dob == null)
.forEach( a -> {
Predicate<B> nameFilter = b -> b.name.equals(a.name);
a.dob = findDob(nameFilter, bList);
});

static String findDob(Predicate<B> nameFilter, List<B> bList) {
B b = bList.stream()
.filter(nameFilter)
.findFirst()
.orElse(new B());

return b.dob;
}

Alternate efficient solution: Considering you have a unique name for each object B, you can prepare lookup and find age using that map, this way you do not need to iterate bList for every iteration of aList

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

Map<String, String> nameDobLookup = bList.stream()
.collect(Collectors.toMap(b -> b.name, b -> b.dob));

aList.stream()
.filter(a -> a.dob == null)
.forEach(a -> a.dob = nameDobLookup.get(a.name));

Update list of object from another list lambda expressions in java 8

I would use streams for that job.

Assuming your class MyObject has getters and setters methods defined (getKey(), getValue(), setKey(), setValue()), you can do:

l1.forEach(myObject1 -> l2.stream()
.filter(myObject2 -> myObject1.getKey().equals(myObject2.getKey()))
.findAny().ifPresent(myObject2 -> myObject1.setValue(myObject2.getValue())));

If you can have duplicate keys then you should modify ifPresent() to forEach():

l1.forEach(myObject1 -> l2.stream()
.filter(myObject2 -> myObject1.getKey().equals(myObject2.getKey()))
.forEach(myObject2 -> myObject1.setValue(myObject2.getValue())));

Update property of two objects in list based on matching objects in other list

If you care about performance, you could convert one of the lists to a lookup map with ID as a key and then update the other list. It would have a complexity of O(N).

You would create a lookup map like so:

Map<Integer, Object2> map = new HashMap<>();
for (Object2 obj : l2) {
map.put(obj.getId(), obj);
}

Or with Streams:

Map<Integer, Object2> map = l2.stream()
.collect(Collectors.toMap(Object2::getId, obj -> obj));

Now you can iterate over first list and update elements with value with help of the map.

l1.stream().forEach(o1 -> o1.setValue2(map.get(o1.getId()).getValue()));

Alternatively, if Object2 only has id and value, you could even create a map<id, value>:

Map<Integer, String> map = new HashMap<>();
for (Object2 obj : list) {
map.put(obj.getId(), obj.getValue());
}

l1.stream().forEach(o1 -> o1.setValue2(map.get(o1.getId())));

populate a List<Object1> based on another List<Object2> using java 8 stream

Why use stream for this? Stream is not the right tool for mutating objects.

Use standard for loops. Makes code easier to understand too.

List<Obligation> obligationList = ...;
List<ObligationStatus> statusList = ...;

// For better performance, make a map
Map<String, ObligationStatus> statusMap = new HashMap<>(statusList.size());
for (ObligationStatus status : statusList)
statusMap.put(status.getTopic(), status);

// Assign status values
for (Obligation obligation : obligationList) {
ObligationStatus status = statusMap.get(obligation.getTopic());
if (status != null) {
ob.setStatus(status.getStatus());
ob.setComment(status.getComment());
}
}

If you want to do some stream logic, the first part is a good candidate:

// For better performance, make a map
Map<String, ObligationStatus> statusMap = statusList.stream()
.collect(Collectors.toMap(ObligationStatus::getTopic, Function.identity()));

UPDATE

Noticed that question code did equalsIgnoreCase(...) when comparing topic values. If that is really needed, change the HashMap to a case-insensitive TreeMap:

Map<String, ObligationStatus> statusMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

The stream version of that gets convoluted, so better keep it old-style.



Related Topics



Leave a reply



Submit