【问题标题】:Efficient way to group by a given list based on a key and collect in same list java 8基于键按给定列表分组并在同一列表中收集的有效方法java 8
【发布时间】:2018-08-27 14:24:52
【问题描述】:

我有以下课程:

class A{
  String property1;
  String property2;
  Double property3;
  Double property4;
}

所以property1和property2是关键。

class Key{
      String property1;
      String property2; 
}

我已经有如下的 A 列表:

List<A> list=new ArrayList<>();

我想使用 key 进行分组并添加到 A 的另一个列表中,以避免列表中有多个具有相同 key 的项目:

Function<A, Key> keyFunction= r-> Key.valueOf(r.getProperty1(), r.getProperty2());

但是在进行分组时,我必须取 property3 的总和和 property4 的平均值。

我需要一种有效的方法来做到这一点。

注意:我已经跳过了给定类的方法。

【问题讨论】:

标签: java-8 java-stream


【解决方案1】:

收集到Map 是不可避免的,因为你想要group 的东西。一种蛮力的方法是:

yourListOfA
      .stream()
      .collect(Collectors.groupingBy(
             x -> new Key(x.getProperty1(), x.getProperty2()),
             Collectors.collectingAndThen(Collectors.toList(),
                   list -> {
                        double first = list.stream().mapToDouble(A::getProperty3).sum();
                        // or any other default
                        double second = list.stream().mapToDouble(A::getProperty4).average().orElse(0D);
                        A a = list.get(0);
                        return new A(a.getProperty1(), a.getProperty2(), first, second);
            })))
     .values();

这可以稍微改进,例如在Collectors.collectingAndThen 中只迭代List 一次,因为需要自定义收集器。写一个没那么复杂……

【讨论】:

    【解决方案2】:

    试试这样:

     Map<A,List<A>> map = aList
                         .stream()
                         .collect(Collectors
                                 .groupingBy(item->new A(item.property1,item.property2)));
    
    List<A> result= map.entrySet().stream()
                .map(list->new A(list.getValue().get(0).property1,list.getValue().get(0).property1)
                        .avgProperty4(list.getValue())
                        .sumProperty3(list.getValue()))
                .collect(Collectors.toList());
    

    并像这样创建avgProperty4sumProperty3 方法

    public A sumProperty3(List<A> a){
      this.property3 = a.stream().mapToDouble(A::getProperty3).sum();
      return this;
    }
    
    public A avgProperty4(List<A> a){
       this.property4 =  a.stream().mapToDouble(A::getProperty4).average().getAsDouble();
       return this;
    }
    

    result = aList.stream().collect(Collectors
                .groupingBy(item -> new A(item.property1, item.property2),
                        Collectors.collectingAndThen(Collectors.toList(), list ->
                                new A(list.get(0).property1, list.get(0).property1)
                                        .avgProperty4(list).sumProperty3(list))
                )
        );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多