简体   繁体   中英

Java Streams .How to Join and combine List of several Objects into one Object?

I have a requirement related to Streams in Java. I need to iterate over a List of Objects,where each object has Integer property and a List property.

What I need is, if same objects has the same ID, I need to concat the lists. Let me illustrate the example with a little bit of a simple code:

Here just defining 2 simple classes:

public static class Wrapper {
  Integer id ;
  List<Element> list;

  public Wrapper(Integer id, List<Element> list) {
    this.id = id;
    this.list = list;
  } 
}

public static class Element {
  String content ;

   public Element(String content) {
       this.content = content;
   } 
 }

Now in a Main Java method,creating same objects for the porpuse of the example:

    List<Wrapper> list=new ArrayList();
    ArrayList<Element> listForWrapper1= new ArrayList();
    listForWrapper1.add(new Element("Content A"));
    listForWrapper1.add(new Element("Content B"));

    ArrayList<Element> listForWrapper2= new ArrayList();
    listForWrapper2.add(new Element("Content C"));
    listForWrapper2.add(new Element("Content D"));

    ArrayList<Element> listForWrapper3= new ArrayList();
    listForWrapper3.add(new Element("Content E"));
    listForWrapper3.add(new Element("Content F"));

     Wrapper wrapper1=new Wrapper(1,listForWrapper1);
     Wrapper wrapper2=new Wrapper(2,listForWrapper2);
     //Here this Wrapper has the same ID than wrapper2
     Wrapper wrapper3=new Wrapper(2,listForWrapper3);


     //Adding Elements to List
     list.add(wrapper1);
     list.add(wrapper2);
     list.add(wrapper3);

As you can see, I am adding 3 Wrappers to the list, BUT 2 of them have the same ID

What I want is when Wrapper IDs are the same in the array,just merge both list. So in this example the result should be:

A list with 2 Element :

Element 1 : Wrapper Object with ID 1,with 2 Elements inside its list property,Element Content A ,and Element Content B

Element 2 : Wrapper Object with ID 2,with 4 Elements inside its list property,Element Content C,Element Content D,Element Content E and Element Content F.

How can I achieve this result using Streams? I cant think any elegant solution!

Thanks in advance!

List<Wrapper> combinedList=list.stream().....

You could use BinaryOperator<U> mergeFunction in Collectors.toMap`.

Collection<Wrapper> wrapperList = wrappers.stream()
        .collect(Collectors.toMap(Wrapper::getId, x -> x),
                (oldVal, newVal) -> {
                    oldVal.getElements().addAll(newVal.getElements());
                    return oldVal;
                }))
        .values();

In the above code I have written mergeFunction to always return oldVal (oldVal, newVal) -> oldVal but you can change the way you want. Lambda function x -> x can also be written as Function.identity() .

You can use Collectors.toMap() to add the values of the map using a merge function.

Map<Integer, Wrapper> collect = 
        list.stream()
            .collect(Collectors.toMap(w -> w.id,
                                      w -> w,
                                      (w1, w2) -> {
                                         w1.list.addAll(w2.list);
                                         return w1;
                                      })
            );

Working

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Wrapper> list=new ArrayList();
        ArrayList<Element> listForWrapper1= new ArrayList();
        listForWrapper1.add(new Element("Content A"));
        listForWrapper1.add(new Element("Content B"));

        ArrayList<Element> listForWrapper2= new ArrayList();
        listForWrapper2.add(new Element("Content C"));
        listForWrapper2.add(new Element("Content D"));

        ArrayList<Element> listForWrapper3= new ArrayList();
        listForWrapper3.add(new Element("Content E"));
        listForWrapper3.add(new Element("Content F"));

        Wrapper wrapper1=new Wrapper(1,listForWrapper1);
        Wrapper wrapper2=new Wrapper(2,listForWrapper2);
        //Here this Wrapper has the same ID than wrapper2
        Wrapper wrapper3=new Wrapper(2,listForWrapper3);


        //Adding Elements to List
        list.add(wrapper1);
        list.add(wrapper2);
        list.add(wrapper3);

Map<Integer, Wrapper> collect =
        list.stream()
            .collect(Collectors.toMap(w -> w.id,
                                      w -> w,
                                      (w1, w2) -> {
                                         w1.list.addAll(w2.list);
                                         return w1;
                                      })
            );
        System.out.println( collect.values() );
    }
}

 class Wrapper {
    Integer id ;
    List<Element> list;

    public Wrapper(Integer id, List<Element> list) {
        this.id = id;
        this.list = list;
    }

     @Override
     public String toString() {
         return id + ":" + list;
     }
 }

 class Element {
    String content ;

    public Element(String content) {
        this.content = content;
    }

     @Override
     public String toString() {
         return content;
     }
 }

Output

[1:[Content A, Content B], 2:[Content C, Content D, Content E, Content F]]

You can try this:

Map<Integer, Wrapper> map = list.stream().collect(Collectors.toMap(wrapper -> wrapper.id /*Use the ids as the keys*/, wrapper -> wrapper /*Return the same wrapper as the value*/, (w1, w2) -> {
         w1.list.addAll(w2.list); // If a wrapper with the same id is found, then merge the list of wrapper 2 to the list of wrapper 1 and return wrapper 1.
         return w1;
     }));

list = new ArrayList<>(map.values()); // Create new ArrayList with the values of the map.



System.out.println(list); // [cci.Test$Wrapper@4eec7777, cci.Test$Wrapper@3b07d329]

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