Я столкнулся с проблемой, когда мне нужен порядок, сохраненный в операции, выполняемой в списке строк, и используя метод collect
из потоков java api.
public List<String> countOccurrences(ArrayList<String> messages) {
List<String> stackedMessages = new LinkedList<>();
HashMap<String, Integer> messageOccurrences =
messages.stream()
.collect(groupingBy(Function.identity(), summingInt(e -> 1))); messageOccurrences.forEach((key, value) -> {
String appendString = value == 1 ? "" : " (" + value + " times)";
stackedMessages.add(key + appendString);
}); return stackedMessages;
}
Проблема с указанным выше кодом заключается в том, что если я обрабатываю список, например ["blah", "blah", "yep"]
, он возвращает ["yep", "blah (2 times)"]
, где мне нужно вернуть ["blah (2 times)", "yep"]
.
Я уже здесь смотрел этот пост и был убежден, что если я использую поток по уже упорядоченной структуре данных, тогда будет обеспечен порядок: Как сделать обеспечить порядок обработки в потоках java8?
Я думаю, мне нужно изменить groupingBy
на toMap
, и на данный момент я читаю через эту документацию. Любой, кто хорошо разбирается в предмете, уже предложит несколько указателей.
ОБНОВЛЕНИЕ:
Благодаря пользователю @ Aominè, это правильный способ сделать это, используя groupingBy
.collect(groupingBy(Function.identity(),LinkedHashMap::new, summingInt(e->1)))
counting()
вместоsummingInt(e -> 1)
. А для последней функции отображенияe.getValue()==1? e.getKey(): e.getKey()+" ("+e.getValue()+" times)"
избегает ненужной конкатенации строк.Вам нужно будет собрать
LinkedHashMap
, чтобы получить ожидаемый результат. Кроме того, вам не нужно делать еще одинforEach
отдельно от конвейера потока послеgroupingBy
, просто создайте поток изentrySet
иmap
, затем заберите в список.