为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 Java 8 Streams 对对象属性进行分组并映射到另一个对象?

如何使用 Java 8 Streams 对对象属性进行分组并映射到另一个对象?

慕森王 2022-05-12 15:37:16
假设我有一组碰碰车,它们的侧面有尺寸、颜色和标识符(“汽车代码”)。class BumperCar {    int size;    String color;    String carCode;}现在我需要将碰碰车映射到一个List对象DistGroup,每个对象都包含属性和size汽车代码。colorListclass DistGroup {    int size;    Color color;    List<String> carCodes;    void addCarCodes(List<String> carCodes) {        this.carCodes.addAll(carCodes);    }}例如,[    BumperCar(size=3, color=yellow, carCode=Q4M),    BumperCar(size=3, color=yellow, carCode=T5A),    BumperCar(size=3, color=red, carCode=6NR)]应该导致:[    DistGroup(size=3, color=yellow, carCodes=[ Q4M, T5A ]),    DistGroup(size=3, color=red, carCodes=[ 6NR ])]我尝试了以下方法,它实际上做了我想做的事情。但问题是它实现了中间结果(到 a 中Map),我也认为它可以立即完成(可能使用mappingorcollectingAndThen或reducingor ),从而产生更优雅的代码。List<BumperCar> bumperCars = …;Map<SizeColorCombination, List<BumperCar>> map = bumperCars.stream()    .collect(groupingBy(t -> new SizeColorCombination(t.getSize(), t.getColor())));List<DistGroup> distGroups = map.entrySet().stream()    .map(t -> {        DistGroup d = new DistGroup(t.getKey().getSize(), t.getKey().getColor());        d.addCarCodes(t.getValue().stream()            .map(BumperCar::getCarCode)            .collect(toList()));        return d;    })    .collect(toList());如何在不使用中间结果的变量的情况下获得所需的结果?编辑:如何在不实现中间结果的情况下获得所需的结果?我只是在寻找一种不会实现中间结果的方法,至少表面上不会。这意味着我不喜欢使用这样的东西:something.stream()    .collect(…) // Materializing    .stream()    .collect(…); // Materializing second time当然,如果这是可能的。请注意,为简洁起见,我省略了 getter 和构造函数。您还可以假设equals和hashCode方法已正确实现。另请注意,我使用的SizeColorCombination是我用作分组键的。这个类显然包含属性size和color。也可以使用诸如Tuple、之类的Pair类或表示两个任意值的组合的任何其他类。编辑:还请注意,当然可以使用 ol' skool for 循环,但这不在此问题的范围内。Entry
查看完整描述

3 回答

?
墨色风雨

TA贡献1853条经验 获得超6个赞

如果我们假设它DistGroup基于hashCode/equalsand size,color你可以这样做:


bumperCars

    .stream()

    .map(x -> {

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

        list.add(x.getCarCode());

        return new SimpleEntry<>(x, list);

    })

    .map(x -> new DistGroup(x.getKey().getSize(), x.getKey().getColor(), x.getValue()))

    .collect(Collectors.toMap(

        Function.identity(),

        Function.identity(),

        (left, right) -> {

            left.getCarCodes().addAll(right.getCarCodes());

            return left;

        }))

    .values(); // Collection<DistGroup>


查看完整回答
反对 回复 2022-05-12
?
萧十郎

TA贡献1815条经验 获得超13个赞

解决方案-1

只需将两个步骤合并为一个:


List<DistGroup> distGroups = bumperCars.stream()

        .collect(Collectors.groupingBy(t -> new SizeColorCombination(t.getSize(), t.getColor())))

        .entrySet().stream()

        .map(t -> {

            DistGroup d = new DistGroup(t.getKey().getSize(), t.getKey().getColor());

            d.addCarCodes(t.getValue().stream().map(BumperCar::getCarCode).collect(Collectors.toList()));

            return d;

        })

        .collect(Collectors.toList());

解决方案-2

groupingBy如果您可以使用属性两次并将值映射为List代码,那么您的中间变量会好得多,例如:


Map<Integer, Map<String, List<String>>> sizeGroupedData = bumperCars.stream()

        .collect(Collectors.groupingBy(BumperCar::getSize,

                Collectors.groupingBy(BumperCar::getColor,

                        Collectors.mapping(BumperCar::getCarCode, Collectors.toList()))));

并简单地使用forEach添加到最终列表中:


List<DistGroup> distGroups = new ArrayList<>();

sizeGroupedData.forEach((size, colorGrouped) ->

        colorGrouped.forEach((color, carCodes) -> distGroups.add(new DistGroup(size, color, carCodes))));

注意:我已经更新了您的构造函数,使其接受卡代码列表。


DistGroup(int size, String color, List<String> carCodes) {

    this.size = size;

    this.color = color;

    addCarCodes(carCodes);

}

进一步将第二个解决方案组合成一个完整的陈述(尽管我自己喜欢forEach老实说):


List<DistGroup> distGroups = bumperCars.stream()

        .collect(Collectors.groupingBy(BumperCar::getSize,

                Collectors.groupingBy(BumperCar::getColor,

                        Collectors.mapping(BumperCar::getCarCode, Collectors.toList()))))

        .entrySet()

        .stream()

        .flatMap(a -> a.getValue().entrySet()

                .stream().map(b -> new DistGroup(a.getKey(), b.getKey(), b.getValue())))

        .collect(Collectors.toList());


查看完整回答
反对 回复 2022-05-12
?
大话西游666

TA贡献1817条经验 获得超14个赞

查看我的图书馆AbacusUtil

StreamEx.of(bumperCars)
         .groupBy(c -> Tuple.of(c.getSize(), c.getColor()), BumperCar::getCarCode)
         .map(e -> new DistGroup(e.getKey()._1, e.getKey()._2, e.getValue())
         .toList();


查看完整回答
反对 回复 2022-05-12
  • 3 回答
  • 0 关注
  • 420 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号