簡體   English   中英

將 `IntStream` 打印為 `String` 的最簡單方法

[英]Simplest way to print an `IntStream` as a `String`

使用 Java-8,我可以使用charscodePoints方法輕松地將String (或任何CharSequence )視為IntStream

IntStream chars = "Hello world.".codePoints();

然后我可以操作流的內容

IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');

我一直在尋找一種整潔的方法來打印結果,但我什至找不到一種簡單的方法。 我如何將這個int流放回可以像String一樣打印的形式。

從上面的stars我希望打印

***** ******
String result = "Hello world."
  .codePoints()
//.parallel()  // uncomment this line for large strings
  .map(c -> c == ' ' ? ' ': '*')
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

但是, "Hello world.".replaceAll("[^ ]", "*")更簡單。 並非一切都從 lambda 中受益。

對 Holger 的解決方案效率稍低但更簡潔:

String result = "Hello world."
    .codePoints()
    .mapToObj(c -> c == ' ' ? " ": "*")
    .collect(Collectors.joining());

Collectors.joining()內部使用StringBuilder ,至少在OpenJDK 源代碼中是這樣

其他答案顯示了如何將字符串流收集為單個字符串以及如何從IntStream收集字符。 此答案顯示了如何在字符流上使用自定義收集器。

如果你想將一個整數流收集到一個字符串中,我認為最干凈和最通用的解決方案是創建一個返回收集器的靜態實用程序方法。 然后你可以像往常一樣使用Stream.collect方法。

可以像這樣實現和使用此實用程序:

public static void main(String[] args){
    String s = "abcacb".codePoints()
        .filter(ch -> ch != 'b')
        .boxed()
        .collect(charsToString());

    System.out.println("s: " + s); // Prints "s: acac"
}

public static Collector<Integer, ?, String> charsToString() {
    return Collector.of(
        StringBuilder::new,
        StringBuilder::appendCodePoint,
        StringBuilder::append,
        StringBuilder::toString);
}

標准庫中沒有這樣的東西,這有點令人驚訝。

這種方法的一個缺點是它需要將字符裝箱,因為IntStream接口不適用於收集器。

一個未解決的難題是實用方法應該命名什么。 收集器實用程序方法的約定是將它們toXXX ,但toString已經被采用。

如果必須的話,我們可以用這種極其丑陋的方式制作單行:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(i -> new String(new int[] { i }, 0, 1)).collect(Collectors.joining());
}

它執行與我的其他答案完全相同的版本,但它一直使用流媒體。 顯然需要一些將單個代碼點轉換為字符串的函數:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(Stars::codePointToString).collect(Collectors.joining());
}

private static String codePointToString(int codePoint) {
    return new String(new int[] { codePoint }, 0, 1);
}

這當然將這些函數放在類Stars中。

我這樣做的方法是使用reduce 要獲取每個字符的*和每個空格的空格,它看起來像這樣

    String hello = "hello world";
    String result = hello.chars()
        .map(val -> (val == ' ') ?  ' ' : '*')
        .mapToObj(val -> String.valueOf((char) val))
        .reduce("",(s1, s2) -> s1+s2);

關鍵是對整數做任何你想做的事情,而不是將它轉換為字符然后將它映射到String然后連接它,你可以使用reduceCollectors.joining()

您可以直接使用以下代碼進行操作:-

"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));

有一個簡單的答案,它不太傾向於使用流媒體做所有事情。 因此,它不是單行的,但它可能更高效且易於閱讀:

public static String stars(String t) {
    StringBuilder sb = new StringBuilder(t.length());
    t.codePoints().map(c -> c == ' ' ? ' ' : '*').forEach(sb::appendCodePoint);
    return sb.toString();
}

有時簡短不等於簡潔,我想沒有人會好奇上面的函數是如何運行的。

此解決方案確保代碼點永遠不會轉換回字符。 因此,它比此處列出的其他一些解決方案更通用。

這個怎么樣。

  System.out.println(stars.mapToObj(c -> String.format("%c", c)).collect(
            Collectors.joining()));

  or

  String s = stars.mapToObj(c -> String.format("%c", c)).reduce("",
            (a, b) -> a + b);
  IntStream charStream = "hello".chars();
  charStream.mapToObj(c -> (char)c).forEach(System.out::println);

這對我有用。

你可以這樣做:

chars.mapToObj(c -> c == ' ' ?  " ": "*").collect(joining());

另一個例子:

以下示例返回原始字符串。 但是這些可以與其他中間操作結合使用,例如filter()

chars.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.joining()));

"abc".chars().mapToObj(i -> "" + (char) i)).collect(Collectors.joining()));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM