【问题标题】:Grouping and replacing groups inside stream, Java 8在流中分组和替换组,Java 8
【发布时间】:2019-10-28 19:34:37
【问题描述】:

我有这样的任务:在排序的字符串流中,将所有 3 个相同字符串的组更改为一个包含大写字母的组(使用 java 8 流 API)。示例:

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}

【问题讨论】:

  • 所以如果b 出现4 次,输出将只是{"a","a","b","b","b","b","c"}{"a","a","B","b","c"}
  • 出现不超过3次,所以是大写字母

标签: java java-8 java-stream grouping collectors


【解决方案1】:

我可以在流中计算相同的字符串,但我不明白如何 替换组,无需额外迭代

如果您要坚持使用流式方法,那么您别无选择,只能通过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 -&gt; e.getKey())...

【讨论】:

    【解决方案2】:

    如果您“看到三重”,请收集到一个列表并倒带。

    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 被替换为知道“三元组”可以跨越两个列表的东西.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-06
      • 1970-01-01
      相关资源
      最近更新 更多