nafas
nafas

Reputation: 5423

how to merge two collections by updating a value on duplicates

I have this class:

class A{
 int count=0;


 //equals and hashCode implemented
}

create two collections:

Collection<A>  collection1;//something
Collection<A>  collection2;//something

concatenate the collections:

Stream.concat(collection1.stream(), collection2.stream())
                //do something here???
                .distinct()
                .sorted(new Comparator<A>() {
                  @Override
                  public int compare(A o1, A o2) {

                     return new Integer(o1.count).compareTo(new Integer(o2.count));
                  }
                })
                .collect(Collectors.toList());

I want to merge these two lists and if there any duplicates, I want to update integer count; the above code gets rid of duplicates completely

For example, say we got an object in both collection1 and collection2 that are equal (o1.equals(o2) == true) . One has count=10 and the other one has count=20 I want to have a collection of distinct objects with that object to have count=30

Is there a way of doing it?

Upvotes: 1

Views: 469

Answers (1)

Ousmane D.
Ousmane D.

Reputation: 56433

You can't do it with your current approach, instead you can use the toMap collector:

Stream.concat(collection1.stream(), collection2.stream())
       .collect(Collectors.toMap(Function.identity(),Function.identity(),
       (left, right) -> {
          left.setCount(left.getCount() + right.getCount());
          return left;
       })).values()
         .stream()
         .sorted(Comparator.comparingInt(A::getCount))
         .collect(Collectors.toList());

This uses Stream.concat to merge collection1 and collection2 together into a single Stream<A>.

We then call the toMap collector where the first Function.identity() selects the elements of the source as the keys i.e A and the second Function.identity() also selects the elements of the source as the values; again A, so at this point, you can visualise the data as Map<A, A>.

The function (left, right) -> { ... } is known as the merge function, this is the place where if two given objects are equal we then say take the count of the first element and take the count of the second element, add them together and assign the new value back to one of the elements we are going to keep and then discard the other.

because you've overridden equals and hashcode, we don't need to explicitly call it, instead, the equals method will be called implicitly to determine if two given objects are equal.

once we've collected the elements to a Map<A, A>, we then call the values() method to retrieve a Collection<A>, this then enables us to create a stream from it with the stream() method and further enables us to sort the streams elements with the sorted method and finally collect it to a List<A> with the toList collector.

Upvotes: 3

Related Questions