java - 如何获取 Java Stream 中每种类型(按属性选择)的第一个对象(按函数排序)

标签 java arrays list java-stream grouping

想象一个具有 3 个属性的简单对象:

public class Obj {

    boolean toBeAdded;
    String type;
    int order;

    public Obj(boolean toBeAdded, String type, int order) {
        this.toBeAdded = toBeAdded;
        this.type = type;
        this.order = order;
    }

    public boolean isToBeAdded() {
        return toBeAdded;
    }

    public String getType() {
        return type;
    }

    public int getOrder() {
        return order;
    }

}

假设我有一个包含多个不同类型的 Obj 的列表:

import java.util.Arrays;
import java.util.List;

public class Utils {

    static List<Obj> createA(){
        List<Obj> list = Arrays.asList(
                new Obj(true, "A", 1),
                new Obj(false, "A", 2),
                new Obj(true, "A", 3),
                new Obj(false, "A", 4)
        );
        return list;
    }


    static List<Obj> createB(){
        List<Obj> list = Arrays.asList(
                new Obj(true, "B", 1),
                new Obj(false, "B", 2),
                new Obj(true, "B", 3),
                new Obj(false, "B", 4)
        );
        return list;
    }


    static List<Obj> createC(){
        List<Obj> list = Arrays.asList(
                new Obj(false, "C", 1),
                new Obj(false, "C", 2),
                new Obj(true, "C", 3),
                new Obj(true, "C", 4)
        );
        return list;
    }
}

我想以某种方式过滤此列表,并为可以添加的每个类型提供最新的Obj(最高order值)(toBeAdded = true)。

对于此示例,结果应该是一个包含以下内容的列表:

  • Obj1:类型 1,顺序 3
  • Obj2:类型 2,顺序 3
  • Obj3:类型 3,顺序 4

我知道如何过滤和如何排序,但我仍然不明白如何获得每个子类型中的第一个。这是否违反 Stream 规则?因为我想做的基本上是解析 N 个不同的子流,针对 N 个不同的 type

这是到目前为止我能做的:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class MainTest {

    public static void main(String[] args) {

        List<Obj> list = new ArrayList<>();
        list.addAll(Utils.createA());
        list.addAll(Utils.createB());
        list.addAll(Utils.createC());

        System.out.println(list);

        List<Obj> filteredList = list
                .stream()
                .filter(Obj::isToBeAdded)
                .sorted(Comparator.comparingInt(Obj::getOrder).reversed())
                .collect(Collectors.toList());

        System.out.println(filteredList);

    }


}

但是,这只是完成简单的部分 - 过滤和排序。我仍然需要为每个 type 执行类似 findFirst() 的操作。有什么办法可以做到这一点吗?

我是否必须执行 3 个不同的流(每种类型一个),然后合并列表?有没有办法在不知道我们将有多少类型的情况下做到这一点? 我还阅读了有关 collect(Collectors.groupingBy()) 的内容,但这会为每种类型创建不同的 map ,这是我不想要的。

最佳答案

使用 groupingBy 以及 minBy/maxBy 的下游可以提供帮助。这将提供一个映射来查找过滤后的值是否存在于每种类型中。

Map<String, Optional<Obj>> groupMaxOrderByType = list.stream()
        .filter(Obj::isToBeAdded)
        .collect(Collectors.groupingBy(Obj::getType,
                Collectors.maxBy(Comparator.comparingInt(Obj::getOrder)))); //highest order

对这些对象的查找或访问将转换为如下内容:

Obj maxPerTypeA = groupMaxOrderByType.get("A").orElse.. // similar for each type

编辑:或者,如果您要将所有此类现有类型收集到最终结果中,您可以按照以下步骤访问Map

List<Obj> result = groupMaxOrderByType.values().stream()
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toList());

编辑:或者摆脱处理Optional,您可以将toMapBinaryOperator.maxBy 作为合并函数。

Map<String, Obj> groupMaxOrderByType = list.stream()
        .filter(Obj::isToBeAdded)
        .collect(Collectors.toMap(Obj::getType, Function.identity(), 
                BinaryOperator.maxBy(Comparator.comparingInt(Obj::getOrder))));
List<Obj> result = new ArrayList<>(groupMaxOrderByType.values());

关于java - 如何获取 Java Stream 中每种类型(按属性选择)的第一个对象(按函数排序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62447199/

相关文章:

python - 如何根据 python 中的条件在列表中组合或保留字符串?

java - 在Java(或一般情况下)中,迭代器应该是可重用的还是设计为一次性使用的?

c++ Bag Of Words聚集数组大小问题

c# - 哪个 winforms 控件/方法绑定(bind)到自定义对象的 List<> 集合?

java - 如何在 JUnit 测试中测试列表?

c++ - 与指针数组混淆

java - 如果一个类扩展了另一个类,是否可以初始化扩展类而不是扩展它?

java - 使用正则表达式提取两个标签之间的文本

java - Android如何从TextView获取String到String

C - 无法将 1 个参数从 int 转换为 int[][4]