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

使用 Java Stream 从 ArrayList 获得最高分

使用 Java Stream 从 ArrayList 获得最高分

茅侃侃 2022-05-25 09:54:42
我想通过 Id 获得最高分组。如果两个最高分相同,那么我想根据最低可选 ID 获得最高分。我想在 Java Stream 中获得它。到目前为止,我正在尝试以下代码这不起作用示例:数组列表:ID:1 Score:80 OptionalId:1ID:1 Score:90 OptionalId:2ID:1 Score:90 OptionalId:3ID:2 Score:80 OptionalId:1ID:2 Score:100 OptionalId:3ID:2 Score: 100 可选 ID:5结果应该是ID:1 得分 90 OptionalId:2ID 2 得分 100 OptionalId:3Map<Long, Optional<Person>> result1 = records.stream()                  .collect(Collectors.groupingBy(Person::getId,                          Collectors.maxBy(Comparator.comparing(Person::getScore)),                          Collector.minBy(Comparator.comparing(Person::getOptionalId))));        for(Person ns: result1) {            sb.append(ns.getBatchNumber());            sb.append(',');
查看完整描述

3 回答

?
慕哥9229398

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

我建议你从一个Comparator<Person>优先考虑最大值 score然后是最小值的自定义开始optionalId。为简洁起见,这是将其传递给变量的好方法:


final Comparator<Person> comparator = Comparator

    .comparing(Person::getScore)                 // descending score first

    .thenComparing(Comparator                    // then ..

        .comparing(Person::getOptionalId)        // .. optionalId

        .reversed());                            // .. but ascending

现在使用一些收集器java流.


Collectors::groupingBy按值和下游对所有Persons进行分组id

Collectors::reducing将所有Person相同的 s减少id为一个,使用Comparator<Person>得到最高score和最低的一个optionalId。

Collectors::collectingAndThenCollection<Optional<Person>>将结构从to展平,Collection<Person>因为任何减少操作都会导致Optional- 此步骤是可选的,可能会根据您的示例跳过。

这是代码:


Collection<Person> filtered = records.stream()         // Stream<Person>

    .collect(Collectors.groupingBy(                    // from Map<Long, List<Person>>

        Person::getId,

        Collectors.collectingAndThen(                  // .. downstream to ..

                Collectors.reducing((a, b) ->          // .. Map<Long, Optional<Person>>

                    comparator.compare(a, b) > 0 ? a : b),

                Optional::get))                        // .. Map<Long, Person>

    .values();                                         // .. Collection<Person>

[人 [id=1, score=90, optionalId=2], 人 [id=2, score=100, optionalId=3]]


查看完整回答
反对 回复 2022-05-25
?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

对于给定的 Id 值,必须有一个 Person。Id 值的存在完全取决于 Person。因此,如果存在 Id,则也必须存在 Person。因此,将 aOptional<Person>作为地图的值有什么意义。相比之下,仅将一个Person实例作为map. 在这里,我将toMap收集器与 一起使用BinaryOperator.maxBy来完成工作。这是它的外观。请注意如何将BinaryOperator.maxBy用作mergeFunction。


Map<Integer, Person> maxPersonById = records.stream()

    .collect(Collectors.toMap(Person::getId, Function.identity(),

        BinaryOperator.maxBy(Comparator.comparing(Person::getScore)

            .thenComparing(Comparator.comparing(Person::getOptionalId).reversed()))));

这是上述给定输入的输出。


{1=Person [id=1, score=90, optionalId=2], 2=Person [id=2, score=100, optionalId=3]}


查看完整回答
反对 回复 2022-05-25
?
月关宝盒

TA贡献1772条经验 获得超5个赞

您可以尝试使用以下聚合的流代码ID,然后使用两级排序找到最大分数,首先是分数,然后是可选的 ID,以防分数平局:


import static java.util.Collections.reverseOrder;

import static java.util.Comparator.comparing;


Map<Long, Optional<Person>> result1 = records.stream()

    .collect(Collectors.groupingBy(Person::getId,

             Collectors.maxBy(

                 Comparator.comparing(Person::getScore)

                  .thenComparing(reverseOrder(comparing(Person::getOptionalId))))));


Optional[ID: 1 Score: 90 OptionalId: 2]

Optional[ID: 2 Score: 100 OptionalId: 3]

这里的技巧是仅反转可选 ID 的排序顺序,我们希望它是升序的,而不是降序的。默认情况下排序顺序为降序,因为我们正在调用Collections.maxBy.


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

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信