我在使用流分组时遇到问题。
List<FAR> listFar = farList.stream().filter(f -> !f.getStatus().equals(ENUM.STATUS.DELETED))
.collect(Collectors.toList());
List<HAUL> haulList = listFar.stream().map(f -> f.getHaul()).flatMap(f -> f.stream())
.collect(Collectors.toList());
按照物种分组,一切都很好,但是还有其他属性。
Map<Specie, List<HAUL>> collect = haulList.stream().collect(Collectors.groupingBy(HAUL::getSpecie));
属性:
haul.getFishCount();
(整数)haul.getFishWeight();
(BigDecimal)是否可以按HAUL::getSpecie
(按Specie)进行分组,还可以将这两个额外字段“合并”在一起,所以我有总数?
例如:我有3个HAUL元素,其中鱼类A的重量为50/30/10千克。
我可以按物种分组并且总重量?
答案 0 :(得分:4)
如果我理解正确:
haulsList
.stream()
.collect(Collectors.groupingBy(HAUL::getSpecie,
Collectors.collectingAndThen(Collectors.toList(),
list -> {
int left = list.stream().mapToInt(HAUL::getFishCount).sum();
BigDecimal right = list.stream().map(HAUL::getFishWeight).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
return new AbstractMap.SimpleEntry<>(left, right);
})));
有一个表格要做:
.stream()
.collect(Collectors.groupingBy(HAUL::getSpecie,
Collectors.summingInt(HAUL::getFishCount)));
或
.stream()
.collect(Collectors.groupingBy(HAUL::getSpecie,
Collectors.mapping(HAUL::getFishWeight, Collectors.reducing((x, y) -> x.add(y)))));
但你真的无法同时采取行动。
答案 1 :(得分:3)
您可以使用mapping
和reduce
例如:
class Foo { int count; double weight; String spice; }
List<Foo> fooList = Arrays.asList(
new Foo(1,new BigDecimal(10), "a"),
new Foo(2,new BigDecimal(38), "a"),
new Foo(5,new BigDecimal(2), "b"),
new Foo(4,new BigDecimal(8), "b"));
Map<String,Optional<BigDecimal>> spieceWithTotalWeight = fooList.stream().
collect(
groupingBy(
Foo::getSpice,
mapping(
Foo::getWeight,
Collectors.reducing(BigDecimal::add)
)
)
);
System.out.println(spieceWithTotalWeight); // {a=Optional[48], b=Optional[10]}
我希望这会有所帮助。
答案 2 :(得分:3)
如果我正确地提出了您的问题,您希望每个物种的总和为count * weight
。
您可以将Collectors.groupingBy
与下游收集器一起使用,将每个物种的HAUL
列表缩减为haul.getFishCount() * haul.getFishWeight()
的总和:
Map<Specie, BigDecimal> result = haulList.stream()
.collect(Collectors.groupingBy(haul -> haul.getSpecie(),
Collectors.mapping(haul ->
new BigDecimal(haul.getFishCount()).multiply(haul.getFishWeight()),
Collectors.reducing(BigDecimal::plus))));
这将获得每个物种的count * weight
总和。如果您可以将以下方法添加到Haul
类:
public BigDecimal getTotalWeight() {
return new BigDecimal(getFishCount()).multiply(getFishWeight());
}
然后,收集流将更容易,更可读:
Map<Specie, BigDecimal> result = haulList.stream()
.collect(Collectors.groupingBy(haul -> haul.getSpecie(),
Collectors.mapping(haul -> haul.getTotalWeight(),
Collectors.reducing(BigDecimal::plus))));
编辑毕竟,您似乎希望每个字段都有单独的金额......
我会使用Collectors.toMap
和合并函数。这是代码:
Map<Specie, List<BigDecimal>> result = haulList.stream()
.collect(Collectors.toMap(
haul -> haul.getSpecie(),
haul -> Arrays.asList(
new BigDecimal(haul.getFishCount()),
haul.getFishWeight()),
(list1, list2) -> {
list1.set(0, list1.get(0).plus(list2.get(0)));
list1.set(1, list1.get(1).plus(list2.get(1)));
return list1;
}));
对于每个物种,这使用2个元素的列表来存储索引0
处的鱼数和指数1
处的鱼重量。