我需要通过谓词将列表拆分为两个列表,其中限制元素将变为 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/