java流按一个字段分组,然后合并所有其他字段

hgtggwj0  于 2021-07-09  发布在  Java
关注(0)|答案(3)|浏览(527)

我在流分组方面有困难。

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(); (大十进制)
有没有可能分组 HAUL::getSpecie (按种类),但也“合并”在一起,这两个额外的领域,所以我有总数?
例如:我有3个拖运元素,其中鱼种a的重量为50/30/10千克。
我能按种类和总重量分组吗?

6uxekuva

6uxekuva1#

你可以用 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]}

我希望这有帮助。

mxg2im7a

mxg2im7a2#

如果我答对了你的问题,你想要 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 ,每一种。

hpcdzsge

hpcdzsge3#

如果我理解正确:

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

但你不能让这些同时发生。

相关问题