Группировка и замена групп внутри потока, Java 8 - PullRequest
0 голосов
/ 28 октября 2019

У меня есть такая задача: в отсортированном потоке строк измените все группы из 3 одинаковых строк на группу, содержащую заглавную букву (используйте API потока java 8). Пример:

input = {"a","a","b","b","b","c"} 

output = {"a","a","B","c"}

Я могу считать те же строки в потоке, но я не понимаю, как заменить группу без дополнительных итераций. Все, что у меня есть сейчас:

Map<String, Long> result = Stream.of("a","a","b","b","b","c")
            .collect(Collectors.groupingBy(Function.identity(), 
                    LinkedHashMap::new, Collectors.counting()));

System.out.println(result);

// текущий выход: {a = 2, b = 3, c = 1}

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Соберите в список и перемотайте, если вы «видите тройку».

List<String> coalesced = Stream.of("a", "a", "b", "b", "b", "c")
  .sequential()
  .collect(LinkedList::new, this::coalesce, List::addAll);
System.out.println(coalesced);

private void coalesce(LinkedList<String> list, String s) {
  if (s.equals(list.peekLast()) &&
      list.size() > 1 &&
      s.equals(list.get(list.size() - 2))) {
    list.removeLast();
    list.removeLast();
    list.add(s.toUpperCase());
  } else {
    list.add(s);
  }
}

Будучи коллектором, он безопасен для потоков, хотя нижеследующее будет работать только для однопоточного потока до тех пор, пока List::addAll не будет заменено чем-то, что знает, что "тройной"может охватывать два списка.

0 голосов
/ 28 октября 2019

Я могу считать те же строки в потоке, но я не понимаю, как заменить группу, без дополнительных итераций

, если вы собираетесь сохранитьс потоковым подходом у вас нет другого выбора, кроме как передавать по потоку через entrySet().

Второе, на что я хотел бы обратить внимание, это то, что вместо использования коллектора counting было бы лучше использоватьtoList сборщик, чтобы немного упростить жизнь, когда мы передаем по entrySet для выполнения дальнейших операций.

т.е.

 Stream.of("a", "a", "b", "b", "b", "c")
       .collect(groupingBy(Function.identity(),
                        LinkedHashMap::new,
                        toList()))
       .entrySet().stream()
       .flatMap(e -> e.getValue().size() == 3 ? Stream.of(e.getKey().toUpperCase()) :
             e.getValue().stream())
       .collect(toList());

для полноты, если вы хотите сохранитьс помощью коллектора counting вы можете:

Stream.of("a", "a", "b", "b", "b", "c")
      .collect(groupingBy(Function.identity(),
                        LinkedHashMap::new,
                        counting()))
      .entrySet().stream()
      .flatMap(e -> e.getValue() == 3 ? Stream.of(e.getKey().toUpperCase()) :
                        Stream.generate(e::getKey).limit(e.getValue()))
      .collect(Collectors.toList());

вы также можете заменить Stream.generate(e::getKey).limit(e.getValue()) на LongStream.range(0, e.getValue()).mapToObj(s -> e.getKey()), если хотите ...

...