加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

lambda – Java 8流由3个字段组合并按sum和count聚合产生单行输

发布时间:2020-12-15 04:38:48 所属栏目:Java 来源:网络整理
导读:我知道在论坛上提出了类似的问题,但他们似乎都没有完全解决我的问题.现在我对 Java 8很新,所以请耐心等待. 我有一个产品列表,例如: Input:name category type costprod1 cat2 t1 100.23prod2 cat1 t2 50.23prod1 cat1 t3 200.23prod3 cat2 t1 150.23prod1 c
我知道在论坛上提出了类似的问题,但他们似乎都没有完全解决我的问题.现在我对 Java 8很新,所以请耐心等待.
我有一个产品列表,例如:

Input:
name    category    type    cost
prod1       cat2     t1      100.23
prod2       cat1     t2      50.23
prod1       cat1     t3      200.23
prod3       cat2     t1      150.23
prod1       cat2     t1      100.23


Output:
Single line (name,category,type) summing the cost and count of products.




Product {
    public String name;
    public String category;
    public String type;
    public int id;
    public double cost;

}

我需要按名称,类别和类型对此进行分组,并生成一个结果
总结这些数据并产生每种产品的总成本和数量.大多数示例显示按两个字段分组并使用单个条件进行聚合.

关于forumn的建议,我想出了这个分组:

public class ObjectKeys {

    ArrayList<Object> keys;

    public ObjectKeys(Object...searchKeys) {

         keys = new ArrayList<Object>();

            for (int i = 0; i < searchKeys.length; i++) {
                keys.add( searchKeys[i] );
            }
    }

}

然后用它如下:

Map<String,Map<String,List<Product>>>> productsByNameCategoryType =
    products.stream().collect(groupingBy(new ObjectKeys(l.name(),l.category(),l.type())))

但是我如何将计数和总和链接到上面的代码?特别是对于超过2个领域的团体.
有一个更好的方法吗?

就像我提到的,我的Java8不是那么好,请帮忙.

解决方法

前提

class Product {
    public String name;
    public String category;
    public String type;
    public int id; 
    //todo:implement equals(),toString() and hashCode()
 }

class Item{
   public Product product;
   public double cost;
}

总结方式

您可以使用Collectors#groupingBy&amp ;;总结按产品分组的项目. Collectors#summarizingDouble.

List<Item> items = ...; 
Map<Product,DoubleSummaryStatistics> stat = items.stream().collect(groupingBy(
            it -> it.product,Collectors.summarizingDouble(it -> it.cost)
));

// get some product summarizing
long count = stat.get(product).getCount();
double sum = stat.get(product).getSum();

//list all product summarizing
stat.entrySet().forEach(it ->
  System.out.println(String.format("%s - count: %d,total cost: %.2f",it.getKey(),it.getValue().getCount(),it.getValue().getSum()));
);

合并具有相同产品的项目

首先,您需要在Item类中添加一个qty字段:

class Item{
   public int qty;
   //other fields will be omitted

   public Item add(Item that) {
        if (!Objects.equals(this.product,that.product)) {
            throw new IllegalArgumentException("Can't be added items"
                     +" with diff products!");
        }
        return from(product,this.cost + that.cost,this.qty + that.qty);
    }

    private static Item from(Product product,double cost,int qty) {
        Item it = new Item();
        it.product = product;
        it.cost = cost;
        it.qty = qty;
        return it;
    }

}

那么您可以使用Collectors#toMap合并具有相同产品的项目:

Collection<Item> summarized = items.stream().collect(Collectors.toMap(
        it -> it.product,Function.identity(),Item::add
)).values();

最后

你可以看到两种方式做同样的事情,但第二种方法更容易在流上运行.以及我在github上检查的两种方式的测试,你可以点击查看更多细节:summarizing items& merge items方式.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读