简体   繁体   中英

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, eg

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.

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

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

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

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

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