如何在Java中按名称对列表列表进行分组

时间:2017-09-30 04:21:29

标签: java list arraylist collections grouping

假设我有一个班级

class X {
    String name;
    int value; 
}

我给了这些对象的多个ArrayList作为例子;

[{A,2}, {B,1}, {C,3}]
[{C,5}, {D,1}]
[{A,3}, {D,1}]

现在我想将列表与具有相同名称的对象合并,并对值进行求和,以使最终输出看起来像

[{A,5}, {B,1}, {C,8}, {D,2}]

我使用HashMap解决了这个问题(这不是必需的),我想知道是否可以使用列表操作合并列表,并在对象的字段上完成添加并显示输出ArrayList本身?

2 个答案:

答案 0 :(得分:1)

扩展ArrayList以构建合并功能。

package com.test;
import java.util.ArrayList;

public class MyArrayList<P> extends ArrayList<Pair> {
    public static void main(String[] args) {
       Pair p1 = new Pair ("A", 2);
       Pair p2 = new Pair ("B", 4);
       Pair p3 = new Pair ("C", 1);

       MyArrayList<Pair> l1 = new MyArrayList<Pair>();
       l1.add(p1);
       l1.add(p2);
       l1.add(p3);

       Pair p4 = new Pair ("A", 5);
       Pair p5 = new Pair ("C", 10);
       Pair p6 = new Pair ("D", 12);

       ArrayList<Pair> l2 = new ArrayList<Pair>();
       l2.add(p4);
       l2.add(p5);
       l2.add(p6);

       l1.merge(l2);
       System.out.println(l1.toJson());

    }

   @Override
   public boolean add(Pair e) {
       Pair p = this.getPair(e);
       if (p == null) return super.add(e);
       p.value += e.value;
       return true;
   }

   public void merge (ArrayList<Pair> list) {
       for(Pair p : list) this.add(p);
   }

   public String toJson() {
       StringBuffer s = new StringBuffer("[");
       for(Pair p : this) s.append("{\"name\":").append("\"").append(p.name).append("\",").append("\"value\":").append(p.value).append("},");
       return s.append("]").deleteCharAt(s.length()-2).toString();
   }

   private Pair getPair (Pair e) {
       for(Pair p : this) if (p.name.equals(e.name)) return p;
       return null;
   }
}

配对课程

package com.test;
public class Pair {
   String name;
   int value;
   public Pair(String name, int value) {
      super();
      this.name = name;
      this.value = value;
   }
}

这是输出

[{"name":"A","value":7},{"name":"B","value":4},{"name":"C","value":11},{"name":"D","value":12}]

答案 1 :(得分:0)

您可以使用JDK 8+之后提供的 stream API。

作为以下给定解决方案的一部分,首先我将所有子列表合并为mainList的{​​{1}},其中包含List列表

  main.stream()
      .flatMap(List::stream)
      .collect(Collectors.toList())

现在,Name可以轻松 groupingby 并计算其值,这将返回Map

.stream()
.collect(Collectors.groupingBy(w -> w.getName(), Collectors.summingInt(w -> w.getValue())))

现在,将所有代码组合在一起

    //create dummy List
    List<xyz> last = new ArrayList<>();

    //merge all list into one and they apply group by to sum
    Map<String, Integer> map = main.stream()
                                   .flatMap(List::stream)
                                   .collect(Collectors.toList())
                                   .stream()
                                   .collect(Collectors.groupingBy(w -> w.getName(), Collectors.summingInt(w -> w.getValue())));

因为,您的最终输出为List。因此,我们遍历地图并将其添加到List

    //add into dummy List
    map.entrySet().stream().forEach((e) -> {
        last.add(new xyz(e.getKey(), e.getValue()));
    });

我将不胜感激任何建议和/或改进。