繁体   English   中英

Java Streams。如何将多个对象的列表加入并合并为一个对象?

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

我对Java中的流有一个要求。 我需要遍历对象列表,其中每个对象都具有Integer属性和List属性。

我需要的是,如果相同的对象具有相同的ID,则需要合并列表。 让我用一些简单的代码来说明示例:

这里只定义了两个简单的类:

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;
   } 
 }

现在,在Main Java方法中,为示例的创建创建相同的对象:

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

如您所见,我将3个包装器添加到列表中,但其中2个具有相同的ID

我想要的是包装器ID在数组中相同时,只需合并两个列表。 因此,在此示例中,结果应为:

包含2个元素的列表

元素1 :ID为1的包装对象,其list属性中包含2个元素,元素内容A和元素内容B

元素2 :ID为2的包装对象,其列表属性中包含4个元素,元素内容C,元素内容D,元素内容E和元素内容F。

如何使用Streams获得此结果? 我想不到任何优雅的解决方案!

提前致谢!

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

您可以在Collectors.toMap中使用BinaryOperator<U> mergeFunction

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

在上面的代码中,我编写了mergeFunction以始终返回oldVal (oldVal, newVal) -> oldVal但是您可以更改所需的方式。 Lambda函数x -> x也可以写为Function.identity()

您可以使用Collectors.toMap()通过合并功能添加地图的值。

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

工作

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;
     }
 }

产量

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

您可以尝试以下方法:

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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM