Bryan J
Bryan J

Reputation: 75

How to stream 2 Lists & modify values in 1

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

Answers (4)

Rea Sand
Rea Sand

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

Oleksandr Pyrohov
Oleksandr Pyrohov

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

Ousmane D.
Ousmane D.

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

ernest_k
ernest_k

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

Related Questions