Сохранять порядок в потоке Java с помощью сбора

Q.H. спросил: 12 мая 2018 в 04:03 в: java

Я столкнулся с проблемой, когда мне нужен порядок, сохраненный в операции, выполняемой в списке строк, и используя метод 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)))

2 ответа

Holger ответил: 13 мая 2018 в 06:01
Я бы использовал counting() вместо summingInt(e -> 1). А для последней функции отображения e.getValue()==1? e.getKey(): e.getKey()+" ("+e.getValue()+" times)" избегает ненужной конкатенации строк.
Есть решение
Aominè ответил: 12 мая 2018 в 06:39

Вам нужно будет собрать LinkedHashMap, чтобы получить ожидаемый результат. Кроме того, вам не нужно делать еще один forEach отдельно от конвейера потока после groupingBy, просто создайте поток из entrySet и map, затем заберите в список.

return messages.stream()
               .collect(groupingBy(Function.identity(), LinkedHashMap::new, summingInt(e -> 1)))
               .entrySet()
               .stream()
               .map(e -> e.getKey()+(e.getValue() == 1 ? "" : " (" + e.getValue() +" times)"))
               .collect(toList());