You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用多Predicate过滤器分组Person列表,以过滤器名为键生成目标Map

按多Predicate分组Person列表的通用实现

需求说明

给定Person类、一组Predicate<Person>过滤器(以名称为键存入filterMap,支持任意数量),需要将输入的List<Person>分组为Map<String, List<Person>>,每个键对应符合对应Predicate的Person列表,要求仅执行一次遍历操作,支持通用处理N个过滤器的场景。

基础定义与示例数据

Person类与过滤器定义

class Person {
    private String status;
    private String id;

    // 构造方法
    public Person(String status) {
        this.status = status;
    }

    public Person(String status, String id) {
        this.status = status;
        this.id = id;
    }

    // Getter方法
    public String getStatus() {
        return status;
    }

    public String getId() {
        return id;
    }
}

// 定义过滤器Predicate
Predicate<Person> completedP = j -> j.getStatus().equalsIgnoreCase("completed");
Predicate<Person> inProgressP = j -> j.getStatus().equalsIgnoreCase("inprogress");
Predicate<Person> nullStatusP = j -> j.getStatus() == null && j.getId() == null;

// 过滤器名称与Predicate的映射
Map<String, Predicate<Person>> filterMap = Map.of(
    "completedP", completedP,
    "inProgressP", inProgressP,
    "nullStatusP", nullStatusP
);

示例输入

Person p1 = new Person("completed");
Person p2 = new Person("completed");

Person p3 = new Person("inprogress");
Person p4 = new Person("inprogress");

Person p5 = new Person(null, null);
Person p6 = new Person(null, null);

List<Person> people = List.of(p1, p2, p3, p4, p5, p6);

期望输出

  • 键completedP对应列表:[p1, p2]
  • 键inProgressP对应列表:[p3, p4]
  • 键nullStatusP对应列表:[p5, p6]

解决方案

高效单次遍历实现

这种方式仅遍历一次people列表,对每个Person检查所有过滤器,将符合条件的对象加入对应分组,是性能最优的实现方式:

// 初始化结果Map,提前为每个过滤器创建空列表
Map<String, List<Person>> result = filterMap.keySet().stream()
    .collect(Collectors.toMap(
        key -> key,
        key -> new ArrayList<>()
    ));

// 单次遍历所有Person,匹配过滤器并分组
for (Person person : people) {
    filterMap.forEach((filterName, predicate) -> {
        if (predicate.test(person)) {
            result.get(filterName).add(person);
        }
    });
}

简洁Stream实现(注意:多遍历)

如果追求代码简洁,也可以用Stream API实现,但该方式会对每个过滤器遍历一次people列表,当过滤器数量N较大时性能会下降:

Map<String, List<Person>> result = filterMap.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        entry -> people.stream()
            .filter(entry.getValue())
            .collect(Collectors.toList())
    ));

互斥过滤器优化

如果你的过滤器是互斥的(一个Person最多匹配一个过滤器),可以在找到第一个匹配项后停止检查,进一步优化性能:

for (Person person : people) {
    for (Map.Entry<String, Predicate<Person>> entry : filterMap.entrySet()) {
        if (entry.getValue().test(person)) {
            result.get(entry.getKey()).add(person);
            break; // 匹配后终止当前Person的过滤器检查
        }
    }
}

说明

  • 所有实现都保证了通用性,无论过滤器数量是3个还是N个,都无需修改核心逻辑。
  • 初始化结果Map时提前创建空列表,避免后续操作出现空指针,同时保证即使没有匹配的Person,结果中也会保留对应过滤器的键和空列表。

内容的提问来源于stack exchange,提问作者curiousengineer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:15:19