java8 group count,Java 8流按3个字段分组,按sum和count聚合产生单行输出

I know there a similar questions asked in the forum but none of them seem to be addressing my problem fully. Now I'm very new to Java 8, so please bear with me.

I have a list of Products, for example:

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;

}

I need to group this by name, category and type and produce a single result that

summarizes this data and produces the total cost and count of each product. Most examples show grouping by two fields and aggregating using single criteria.

Following suggestions on the forumn, i came up with this for groupings:

public class ObjectKeys {

ArrayList keys;

public ObjectKeys(Object...searchKeys) {

keys = new ArrayList();

for (int i = 0; i < searchKeys.length; i++) {

keys.add( searchKeys[i] );

}

}

}

Then used it as follows:

Map>>> productsByNameCategoryType =

products.stream().collect(groupingBy(new ObjectKeys(l.name(), l.category(),l.type())))

But how do I chain count and sum to the the above code? Especially for group by with more than 2 fields.

Is there a better way to do this?

Like I mentioned my Java8 is not that good, please help.

解决方案

Precondition

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;

}

Summarizing way

you can summarizing items grouping by product by using Collectors#groupingBy & Collectors#summarizingDouble.

List items = ...;

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

);

Merges Items with Same Product

First, you need adding a qty field in Item class:

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;

}

}

then you can using Collectors#toMap to merges items with same product:

Collection summarized = items.stream().collect(Collectors.toMap(

it -> it.product,

Function.identity(),

Item::add

)).values();

Finally

you can see both ways doing the same thing, but the second approach is easier to operates on a stream. and the tests of two ways I having checked in github, you can click and see more details: summarizing items & merge items ways.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值