java - 有限制的分区

标签 java collections java-8 java-stream

我需要通过谓词将列表拆分为两个列表,其中限制元素将变为 true部分。
例如。假设我有这样的列表:A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]我想按谓词 o -> o % 2 == 0 拆分它并限制 3 .
我想得到 Map<Boolean, List<Integer>>其中:

true -> [2, 4, 6] // objects by predicate and with limit (actually, order is not important)
false -> [1, 3, 5, 7, 8, 9, 10]  // All other objects

Java 8 具有按谓词拆分流的收集器 - Collectors.partitioningBy(...) ,但它不支持限制。是否可以使用 java 8 流/ Guava /apache 来执行此操作,还是我应该创建自己的此功能实现?

编辑:我写了这个函数。如果您对此有任何建议,请随时告诉我。 MultiValuedMap是可选的,可以替换为 Map .

private <E> MultiValuedMap<Boolean, E> partitioningByWithLimit(Predicate<E> predicate, List<E> src, int limit) {
    MultiValuedMap<Boolean, E> result = new ArrayListValuedHashMap<>();
    Iterator<E> iterator = src.iterator();
    while (iterator.hasNext()) {
        E next = iterator.next();
        if (limit > 0 && predicate.test(next)) {
            result.put(true, next);
            iterator.remove();
            limit--;
        }
    }
    result.putAll(false, src);
    return result;
}

最佳答案

这是一种基于自定义收集器的方法:

public static <E> Collector<E, ?, Map<Boolean, List<E>>> partitioningByWithLimit(
        Predicate<E> predicate,
        int limit) {

    class Acc {
        Map<Boolean, List<E>> map = new HashMap<>();

        Acc() {
            map.put(true, new ArrayList<>());
            map.put(false, new ArrayList<>());
        }

        void add(E elem) {
            int size = map.get(true).size();
            boolean key = size < limit && predicate.test(elem);
            map.get(key).add(elem);
        }

        Acc combine(Acc another) {
            another.map.get(true).forEach(this::add);
            another.map.get(false).forEach(this::add);
            return this;
        }
    }

    return Collector.of(Acc::new, Acc::add, Acc::combine, acc -> acc.map));
}

我正在使用本地 Acc 类来包装 map 并公开逻辑以将流的元素累积和组合到 map 中。该映射根据提供的谓词和限制进行分区。

最后,我用 Collector.of 收集流.

用法:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Map<Boolean, List<Integer>> map = list.stream()
        .collect(partitioningByWithLimit(n -> n % 2 == 0, 3));

输出是:

{false=[1, 3, 5, 7, 8, 9, 10], true=[2, 4, 6]}

这种方法的主要优点是它还支持并行流。

关于java - 有限制的分区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44025025/

相关文章:

java - Android 应用程序正确读取字符串列,但不能正确读取第三个整数(sqlite)

java - 如何在没有冗余计算的情况下过滤和映射 Java 8 流中的值?

c# - linq从属性等于值的对象数组中删除项目

java-8 - 如何将 Java 8 流收集到 Guava ImmutableCollection 中?

java - 使用 Java-8 AES/GCM 验证/加密部分数据 block

java - JButton 的 ActionListener 正在响应,但代码显然没有被执行,但是当我直接调用方法时,它却被执行了。非常奇怪的行为?

java.lang.NoClassDefFoundError : io/dropwizard/jetty/RequestLogFactory when using dropwizard

java - 我无法多态地访问具体类的方法

java - 如何使用 Java 8 在 Spring boot 中获取目录(而不是文件)的完整系统路径

c# - 在 C# 中,是否可以循环遍历相同基类型的多个集合?