5

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.

7
  • 2
    I doubt that you can find a solution that is more elegant than two nested loop. For larger lists, converting one list to a Map and doing only one loop has a point, but for such short lists, it won’t pay off. Commented Aug 27, 2018 at 12:07
  • Does person class has only three fields? do you want to update only two fields(name and age) from the other list? Commented Aug 27, 2018 at 12:08
  • @pvpkiran hi, it may have more fields. Since any field maybe updated, I'd like to replace the objects from the new list directly to the old list. Commented Aug 27, 2018 at 12:10
  • There are many details missing. what if some id's are not present in the updatedList? And how big a list are we talking about? Commented Aug 27, 2018 at 12:11
  • 1
    What do you mean by "operators" and Is there a reason you want to use streams? Using Collection methods removeAll, retainAll, and addAll. might be enough and might help readability. For small lists the performance would not be different, I think. Commented Aug 27, 2018 at 13:52

4 Answers 4

3

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
Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

0

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.