【问题标题】:How to control peek to treat the last element differently?如何控制 peek 以区别对待最后一个元素?
【发布时间】:2018-07-23 14:57:47
【问题描述】:

我有一个像

这样的字符流
"abcd".chars()

我正在使用 peek 打印这样的流

"abcd".chars().peek(e->System.out.print(e + ":"))

唯一的问题是它打印为

a:b:c:d:

我想用换行符替换最后一个冒号,但不知道该怎么做,有人可以帮忙吗?

【问题讨论】:

  • 这能编译吗?
  • 预期输出是什么?
  • 期望有 a:b:c:d

标签: java string java-8 java-stream


【解决方案1】:

使用joining 收集器是另一种选择:

String result = Arrays.stream(string.split(""))
                      .collect(Collectors.joining(":"));

或:

String result = Pattern.compile("")
                       .splitAsStream(string)
                       .collect(Collectors.joining(":"));

如果你真的想要一个新行,那么使用 joining 收集器的重载

Collectors.joining(":","","\n")

【讨论】:

  • @YCF_L 赞赏:)。如果 OP 只是想要 "a:b:c:d" 没有新行作为后缀,那么您的 String = String.join(":", string.split("")); 方法对我来说是可行的方法,但如果他们真的想要提到的新行后缀,那么我会只需使用重载Collectors.joining(":","","\n"),因为它比 for 循环更简单、更易读。
  • 我同意@Aominè :)
  • @Aominè 我喜欢这个+1(最后一个代码被剪断),缺点是仅仅为了打印它需要将它们连接到一个新的字符串......
  • @Eugene 感谢! :)。我想这因人而异,但我个人认为创建 一个额外的 新字符串是您不应该考虑/担心的事情吗?尤其是在这个具体的例子中。
  • @Eugene 是的,也许如果流的源很大,那么构建字符串需要更多时间,并且还需要分配一个新字符串。所以,我明白你的意思;-)
【解决方案2】:

那里可能有一两个重复,但如果您不需要特别使用peek(),只需执行以下操作:

String str = "abcd";
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length; i++) {
    System.out.print((i == str.length() - 1) ? arr[i] + "\n" : arr[i] + ":");
}

输出:

a:b:c:d

【讨论】:

    【解决方案3】:

    实现你想要的并不容易,因为你没有办法在peek() 中得到index。如果您坚持使用 peek,我想使用它:

    String string = "abcd";
    AtomicInteger count = new AtomicInteger(0);
    string.chars()
            .peek(e -> {
                System.out.print((char) e);
                if (count.incrementAndGet() != string.length()) {
                    System.out.print(":");
                } else {
                    System.out.println();
                }
            })...
    

    输出

    a:b:c:d
    

    请注意,peek 之后您仍然必须使用终端操作,例如 sum()


    或者更容易你可以像这样使用String.join

    String string = "abcd";
    string = String.join(":", string.split(""));
    

    【讨论】:

      【解决方案4】:

      简短的回答是:你不能。

      Streams 用于对可能无限数量的元素进行可能的并行计算。因此,您无法访问index(索引是数据集中元素的位置还是并行流中对计算的调用次数,其中不保证顺序?)或@987654324 @(无穷大)。

      但是,对于受控遍历,您可以使用 BaseStream#iterator()BaseStream#spliterator() 转换流

      通过在外部跟踪位置,您可以减少并行计算的可能性,并且通过引用流的数据源,您可以限制代码处理非无限数据流。无论哪种方式,它都应该给您一个提示,即 Streams 不是您尝试实现的目标的正确工具。

      【讨论】:

        【解决方案5】:

        您可以尝试使用IntStream.range

        @Test
        public void printChars() {
            String str = "abcd";
            IntStream.range(0, str.length())
                    .mapToObj(i -> str.charAt(i) + (i < str.length()-1 ? ":" : "\n"))
                    .forEach(System.out::print);
        }
        

        输出:

        a:b:c:d
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-25
          • 2019-12-06
          • 2019-02-02
          • 2016-12-07
          • 2013-04-11
          相关资源
          最近更新 更多