Reputation: 75
I would like to iterate over 2 lists to update values in 1. Following is a simplified version of what I am trying to do using nested for loops.
The commented out code is as far as I got trying to utilize streams. Assume that last name is unique. The values I will be comparing in the actual code will in fact be unique.
If anyone could point me in the right direction, I would appreciate it.
List<Person> list1 = new ArrayList<>();
List<Person> list2 = new ArrayList<>();
list1.add(new Person("Jane", "Doe"));
list1.add(new Person("John", "Smith"));
list2.add(new Person("", "Doe"));
list2.add(new Person("", "Smith"));
for (Person p1 : list1) {
for (Person p2 : list2) {
if (p1.getLastName().equals(p2.getLastName())) {
p2.setFirstName(p1.getFirstName());
break;
}
}
}
System.out.println(list2.toString());
//list1.stream()
// .filter(e -> (list2.stream()
// .filter(d -> d.getLastName()
// .equals(e.getLastName()))
Upvotes: 3
Views: 226
Reputation: 173
As you want to solve your problem with streams I suppose you want to dive into functional programming. If that is the case I'd suggest you take a step back and try to internalize the basic principles of functional programming, so you can begin to approach a problem like this with a functional programming mindset. In this specific case that means: don't update your data structure(s) in place, but return a new instance with updated values instead (holding true for both your list and your person entity) and avoid running side-effectful blocks of code. Always return a meaningful value from an operation.
Considering this I'd suggest the following approach:
final List<Person> combined = list1.stream()
.flatMap(p1 -> list2.stream().filter(p2 -> p2.lastname().equals(p1.lastName())).map(p2 -> new Person(p1.firstName(), p2.lastName())))
.collect(Collectors.toList())
Maybe you can take this as a starting point.
Upvotes: 0
Reputation: 16216
Classic for
loops seems to be the best option. The Stream
solution could be as follows:
list1.forEach(p1 ->
list2.stream().filter(p2 -> p1.getLastName().equals(p2.getLastName()))
.findFirst()
.ifPresent(p2 -> p2.setFirstName(p1.getFirstName())));
Upvotes: 2
Reputation: 56423
Here another way to go about it:
list1.forEach(p1 -> list2.stream()
.filter(p2 -> p1.getLastName().equals(p2.getLastName()))
.findFirst()
.ifPresent(p2 -> p2.setFirstName(p1.getFirstName()))
);
or:
list1.forEach(p1 -> list2.stream()
.filter(p2 -> p1.getLastName().equals(p2.getLastName()))
.limit(1)
.forEach(p2 -> p2.setFirstName(p1.getFirstName()))
);
Upvotes: 1
Reputation: 45309
You can create a <lastName, firstName>
map and use it to update the second list:
Map<String, String> lastNameMap = list1.stream()
.collect(Collectors.toMap(Person::getLastName, Person::getFirstName));
list2.stream().forEach(p -> p.setFirstName(lastNameMap.get(p.getLastName())));
Note that this assumes that there are no duplicate last names, any duplicate last name may cause confusion.
As the collect
call is written above, it will fail on duplicate lastName
values, and maybe that should be kept as is so that an error can prevent last name/first name mix up.
Upvotes: 2