То, что вы делаете, сравнимо с 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
для этой цели, что сделает его более читабельным.
Поток в этом примере не улучшает ваш код с точки зрения читабельности, но позволяет использовать параллельную обработку. Посмотрите на третий параметр метода сбора. Он объединяет два промежуточных результата в случае параллельной обработки потока.
Чтобы попробовать его параллельно, замените stream()
на parallelStream()
и поместите sysout
в лямбду третьего параметра, чтобы увидеть, когда объединяются два промежуточных результата. Обратите внимание, что параллельная обработка принесет вам пользу только в том случае, если ваш список очень большой.