Abu Ruqaiyah
Abu Ruqaiyah

Reputation: 1546

Update one list based on another list using stream

I'd like to update items in an existing list from an incoming list.

class Person{
  String id;
  String name;
  String age;
.
.
.
  @Override
  public boolean equals(Object object) {
    return ... ((Person) object).id.equals(this.id);
  }
}

The current list is shorter:

ArrayList<Person> currentList = Arrays.asList(
   new Person("0", "A", 25),
   new Person("1", "B", 35)
);

The received list is bigger, e.g.

ArrayList<Person> updatedList = Arrays.asList(
       new Person("0", "X", 99),
       new Person("1", "Y", 100),
       new Person("2", "C", 2),
       new Person("3", "D", 3),
       new Person("4", "E", 5)
    );

including the items(identified by their id) from current list.

I'd like to replace all the items in the current list, with the same one's from new list.

So after transformation, current list will be

{ Person(0, "X", 99), Person(1, "Y", 100) }

Is it possible to do with Stream only.

Upvotes: 4

Views: 11341

Answers (4)

Manasi
Manasi

Reputation: 765

Yes it is possible using stream,

  1. Find list of ids required from currentList
  2. filter record having ids in first list

    List<String> ids = currentList.stream().map(Person::getId).collect(Collectors.toList());
    currentList = updatedList.stream().filter(o -> ids.contains(o.getId()))
                                      .collect(Collectors.toList());
    

Upvotes: 0

Dakshinamurthy Karra
Dakshinamurthy Karra

Reputation: 5463

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());

Upvotes: 1

Nikolas
Nikolas

Reputation: 44398

If the currentList is always a subset of the updatedList - means that all the currentList will appear in the updatedList, you can do the following:

Set<String> setOfId = currentList.stream()
                                 .map(person -> person.getId()) // exctract the IDs only
                                 .collect(Collectors.toSet());  // to Set, since they are unique

List<Person> newList = updatedList.stream()                     // filter out those who don't match
                                  .filter(person -> setOfId.contains(person.getId()))  
                                  .collect(Collectors.toList());

If the updatedList and currentList differ significantly - both can have unique persons, you have to do the double iteration and use Stream::map to replace the Person. If not found, replace with self:

List<Person> newList = currentList.stream()
    .map(person -> updatedList.stream()                                       // map Person to
                              .filter(i -> i.getId().equals(person.getId()))  // .. the found Id
                              .findFirst().orElse(person))                    // .. or else to self
    .collect(Collectors.toList());                                            // result to List

Upvotes: 3

pvpkiran
pvpkiran

Reputation: 27038

This will achieve what you are asking.

 Map<String, Person> collect = updatedList
                               .stream()
                               .collect(Collectors.toMap(Person::getId, Function.identity()));

 currentList = currentList
               .stream()
               .map(Person::getId)
               .map(collect::get)
               .collect(Collectors.toList());

As @Holger mentioned, doing this for a small List is not so elegant

Upvotes: 0

Related Questions