web-dev-qa-db-ja.com

`IntStream`を` String`として出力する最も簡単な方法

Java-8では、StringまたはCharSequenceのいずれかを使用して、IntStream(または任意のchars)をcodePointsとして簡単に処理できます。方法。

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

その後、ストリームのコンテンツを操作できます

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

結果を印刷するための整頓された方法を探していましたが、簡単な方法さえ見つけることができませんでした。 intsのこのストリームを、Stringのように印刷できる形式に戻すにはどうすればよいですか。

上記からstars印刷したい

***** ******
42
OldCurmudgeon
_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("[^ ]", "*")は簡単です。すべてがラムダの恩恵を受けるわけではありません。

34
Holger

Holgerのより効率的ではないが、より簡潔なソリューション:

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

Collectors.joining()は、少なくとも OpenJDKソースStringBuilderを内部的に使用します。

19
Lukasz Wiktor

他の回答は、文字列のストリームを単一の文字列に収集する方法と、IntStreamから文字を収集する方法を示しています。この回答は、キャラクターのストリームでカスタムコレクターを使用する方法を示しています。

Intのストリームを文字列に収集する場合、最もクリーンで一般的なソリューションは、コレクターを返す静的ユーティリティメソッドを作成することだと思います。次に、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);
}

標準ライブラリにこのようなものがないことは少し驚くべきことです。

このアプローチの欠点の1つは、IntStreamインターフェイスがコレクターで機能しないため、文字をボックス化する必要があることです。

解決されていない難しい問題は、ユーティリティメソッドの名前です。コレクターユーティリティメソッドの規則は、toXXXを呼び出すことですが、toStringは既に使用されています。

6
Lii

必要に応じて、この非常にい方法でワンライナーを作成できます。

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

my other answer とまったく同じバージョンを実行しますが、ストリーミングをずっと使用します。単一のコードポイントを文字列に変換するいくつかの関数が明らかに必要です。

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に配置します。

1
Maarten Bodewes

reduceを使用する方法です。各文字に対して*を取得するには、次のようになります。

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

ポイントはintegersでやりたいことをcharactersにキャストしてからStringにマップしてからconcatenateそれは、reduceまたはCollectors.joining()を使用できます

1
Ahmad

これはどう。

  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);
0
WJS

単純な答えがありますが、これはストリーミングですべてを行うことにやや傾いています。したがって、これは1行ではありませんが、おそらくより効率的で非常に読みやすいでしょう。

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

時にはshortは簡潔と同じではなく、上記の関数がどのように動作するのか不思議に思う人はいないと思います。

このソリューションにより、コードポイントが文字に戻されないことが保証されます。したがって、ここにリストされている他のソリューションよりも多少一般的です。

0
Maarten Bodewes

次のコードで直接行うことができます:-

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

できるよ:

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