0
Person elpidio = new Person.Builder().id(3L).firstName("elpidio").secondName("gomez").ext("121").build();

Person romual1 = new Person.Builder().id(4L).firstName("romualdo").secondName("perez").ext("141").build();

Person romual2 = new Person.Builder().id(4L).firstName("romualdo").secondName("perez").ext("144").build();

Now I need a out put some thing like this.

[Person [firstName=elpidio, secondName=gomez,ext=[121]],
 Person [firstName=romualdo, secondName=perez,ext=[121,144]]]

I refereed to below ans. But the problem I found is that I have many property in Person, and out of that I just need to merge one fields. So the entry set is giving issue. Any suggestion in welcome.

Extract duplicate objects from a List in Java 8

How to merge child objects in list based on duplicate parent object

Arindam
  • 675
  • 8
  • 15
  • Show us your entity class `Person`, in `Person` class for merged property need to be a list and how you check two `Person` object is equal and need to merge ? Any identifier field/fields ? And also check your example may be it is wrong. – Eklavya Aug 28 '20 at 11:27
  • What should be `key` in your case? How `firstName="elpidio"` is reassigned to `id=4` in the output? – Nowhere Man Aug 28 '20 at 11:28
  • Your example doesn't make sense and output doesn't match, so I'll guess you want to "merge" based on id. What you could do: maintain a map with id being the key and `Person` being the value, look up existing values when you try to add a new element and if there is one merge the two as you see fit (e.g. only add the values of the `ext` list/set to the list/set of the existing person). – Thomas Aug 28 '20 at 11:34
  • Updating my question for more readability. So basically what i wnated is that I want to merge two firstName (Key), with Single array of ext. May be some thing like this { firstName : romualdo, ext : [121,144] } – Arindam Aug 28 '20 at 13:30
  • @Thomas yes, some thing like this. – Arindam Aug 28 '20 at 13:33

3 Answers3

2

This is just one way to do it (and probably an overly convoluted, not-so-great way that I haven't completely checked for everything). What I like about this is that it shows how to make a collector of your own, and they are fairly useful to understand those underpinnings. Hopefully the comments are explanation enough. If not, there are lots of guides on custom collectors (like this)

Person elpidio = Person.Builder().id(3L).firstName("elpidio").secondName("gomez").ext("121").build();
Person romual1 = Person.Builder().id(4L).firstName("romualdo").secondName("perez").ext("141").build();
Person romual2 = Person.Builder().id(4L).firstName("romualdo").secondName("perez").ext("144").build();
Map<Long,Person> filteredPersons = Stream.of( elpidio, romual1, romual2 ).collect(Collector.of(
        HashMap::new,  // Starts with an empty list
        (result,entry) -> {
            if ( result.containsKey(entry.id)) {
                // If we already have this id in our map, we add the ext to the result list. This is assuming
                // "ext" in Person is a collection of some sort (because I don't feel like going through the
                // process of creating a new arbitrary class - in other words, that exercise is left for the
                // reader =) If you don't want dupes of ext, make sure it's a set or something else that will
                // remove dupes
                result.get(entry.id).ext.addAll(entry.ext);
            } else {
                result.put(entry.id, entry);
            }
        },
        (result1, result2) -> {
            // This handles the case where the collect is handled in parallel. How do we merge two resulting
            // maps?
            // In this case we are arbitrarily calling "result1" the version to check against, but it really
            // doesn't matter.
            for ( Map.Entry<Long,Person> person : result2.entrySet() ) {
                if ( result1.containsKey(person.getKey()) ) {
                    result1.get(person.getKey()).ext.addAll(person.getValue().ext);
                } else {
                    result1.put(person.getKey(), person.getValue());
                }
            }
            return result1;
        }));
filteredPersons.forEach( (k,v) -> System.out.println( k + " - first: " + v.first + " second: " + v.second + " " +
        "ext: " + v.ext));

outputs:

3 - first: elpidio second: gomez ext: [121]
4 - first: romualdo second: perez ext: [141, 144]
Gryphon
  • 384
  • 1
  • 9
2

There are a lot of ways to solve this question. However you if you want the answer as per your reference.

            persons.stream()
            .collect(Collectors.groupingBy(Function.identity(), toList()))
            .entrySet()
            .stream()
            .map(x -> {
                List<String> exFields = x.getValue().stream().map(Person::getExField).flatMap(Collection::stream).collect(toList());
                Person duplicatePerson = x.getKey();
                duplicatePerson.setExField(exFields);
                return duplicatePerson;
            }).collect(toList());

Explanation. Here we are trying to group objects if certain fields are same in object. This can be done by overridinng the equals and HashCode method. like

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return Objects.equals(id, person.id) &&
            Objects.equals(firstName, person.firstName) &&
            Objects.equals(lastName, person.lastName);
}

@Override
public int hashCode() {
    return Objects.hash(id, firstName, lastName);
}

With this much in place you will be able to get your entrySet. Keys of the entrySet as the duplicate object (any object with those three fields) and value will be a list containing all those duplicate objects. Now from this duplicate list you only need that exFields from each object so this is the code

List<String> exFields = x.getValue().stream().map(Person::getExField).flatMap(Collection::stream).collect(toList());

Why I had to use flatMap ?

Once you get the list of all the exFields you assign that list to your duplicate object.

 duplicatePerson.setExField(exFields);

Finally Collect.

Tushar Jajodia
  • 433
  • 5
  • 15
-1

You can use Java 8 Api Stream in order to filter them by id using a predicate or use distinct()

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

Hilmi Reda
  • 94
  • 7