我想用Java 8流一个接一个地计算相同对象的数量。我该怎么做?如果我有一份清单
3, 3, 5, 5, 5, 6, 3, 3
我希望结果是
[3-2] [5-3] [6-1] [3-2]
我在没有Java 8 streams的情况下的幼稚尝试:
private static List<ValueCount> counteSameValueInRow(List<Integer> Values) {
List<ValueCount> result = new ArrayList<ValueCount>();
ValueCount valueCount = null;
for (int value: Values) {
if (valueCount == null) {
valueCount = new ValueCount(value);
} else if (valueCount.value == value){
valueCount.numberof++;
} else {
result.add(valueCount);
valueCount = new ValueCount(value);
}
}
result.add(valueCount);
return result;
}
发布于 2018-06-27 17:11:02
您正在做的事情可以与流上的collect
相比较。将每个数字汇总到一个“组”列表中。Collectors.groupingBy()
出现在脑海中,但这将对整个列表中的数字进行分组,即只计算每个数字的出现次数。使用Stream.collect(Supplier, BiConsumer, BiConsumer)
方法实现自定义收集,您可以执行以下操作:
List<Integer> values = Arrays.asList(3, 3, 5, 5, 5, 6, 3, 3);
values.stream().collect(LinkedList<List<Integer>>::new, (list, value) -> {
if (list.isEmpty() || !list.getLast().get(0).equals(value))
{
list.add(new ArrayList<>());
}
list.getLast().add(value);
}, (list1, list2) -> {
if (list1.getLast().get(0).equals(list2.getFirst().get(0)))
{
list1.getLast().addAll(list2.getFirst());
list2.removeFirst();
}
list1.addAll(list2);
}).forEach(group -> System.out.println("[" + group.get(0) + "-" + group.size() + "]"));
请注意,我使用ArrayList
s来收集重复项。您可以使用ValueCount
类来实现此目的,这可能会使其更具可读性。
此示例中的流不会提高代码的可读性,但可以使用并行处理。看看collect方法的第三个参数。其中一个合并了两个中间结果,以防流被并行处理。
要并行尝试,请将stream()
替换为parallelStream()
,并在第三个参数的lambda中放置一个sysout
,以查看两个中间结果何时合并。请注意,只有在列表非常大的情况下,并行处理才会使您受益。
发布于 2018-06-27 20:01:04
在Malte Hartwig的提议之后,我进行了重构以获得更好的可读性。结果如下所示
public static void main(String[] args) {
List<Integer> values = Arrays.asList(3, 3, 5, 5, 5, 6, 3, 3);
BiPredicate<Integer, Integer> predicate = (value1, value2) -> value1.equals(value2);
Supplier<BiConsumer<LinkedList<ValueCount>, Integer>> accumulator =
() -> (list, value) -> {
if (list.isEmpty() || !predicate.test(list.getLast().getFirstValue(), value)) {
list.add(new ValueCount());
}
list.getLast().add(value);
};
Supplier<BiConsumer<LinkedList<ValueCount>, LinkedList<ValueCount>>> combiner = () -> (list1, list2) -> {
if (list1.getLast().getFirstValue().equals(list2.getFirst().getFirstValue())) {
list1.getLast().addAll(list2.getFirst());
list2.removeFirst();
}
list1.addAll(list2);
};
values.stream().collect(LinkedList::new, accumulator.get(), combiner.get())
.forEach(group -> System.out.println(group));
}
private static class ValueCount {
private List<Integer> lista = new ArrayList<>();
public String toString() { return "[" + lista.get(0) + "-" + lista.size() + "]";}
public void add(Integer value) { lista.add(value);}
public Integer getFirstValue() { return lista.get(0);}
public void addAll(ValueCount first) { lista.addAll(first.getAll());}
private Collection<? extends Integer> getAll() { return lista;}
}
https://stackoverflow.com/questions/51058350
复制相似问题