【问题标题】:Preserve order in Java stream with collect使用 collect 在 Java 流中保留顺序
【发布时间】:2018-06-05 17:43:26
【问题描述】:

我遇到了一个问题,我需要在对字符串列表执行的操作中保留顺序并使用 java 流 api 中的 collect 方法。

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"]

我已经在这里查看了这篇文章,并相信如果我在已排序的数据结构上使用流,那么将确保顺序:How to ensure order of processing in java8 streams?

我想我需要将 groupingBy 更改为 toMap 并且现在我正在阅读该文档。任何已经精通该主题的人,请提供一些指示。

更新:

感谢用户@Aominè,这是使用 groupingBy 的正确方法

.collect(groupingBy(Function.identity(),LinkedHashMap::new, summingInt(e->1)))

【问题讨论】:

  • 你在迭代一个HashMap,没有顺序。
  • 使用 .collect(groupingBy(Function.identity(),LinkedHashMap::new, summingInt(e->1)))
  • 再次拯救这一天@Aominè,谢谢

标签: java functional-programming java-stream


【解决方案1】:

您需要收集到LinkedHashMap 以获得预期结果。此外,您不必在groupingBy 之后与流管道分开执行另一个forEach,只需从entrySetmap 创建一个流,然后收集到列表。

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());

【讨论】:

  • 我会使用counting() 而不是summingInt(e -&gt; 1)。而对于最后一个映射函数,e.getValue()==1? e.getKey(): e.getKey()+" ("+e.getValue()+" times)" 避免了不必要的字符串连接。
猜你喜欢
  • 2023-04-10
  • 2012-05-31
  • 2014-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多