Java-8では、String
またはCharSequence
のいずれかを使用して、IntStream
(または任意のchars
)をcodePoints
として簡単に処理できます。方法。
IntStream chars = "Hello world.".codePoints();
その後、ストリームのコンテンツを操作できます
IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');
結果を印刷するための整頓された方法を探していましたが、簡単な方法さえ見つけることができませんでした。 int
sのこのストリームを、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("[^ ]", "*")
は簡単です。すべてがラムダの恩恵を受けるわけではありません。
Holgerのより効率的ではないが、より簡潔なソリューション:
_String result = "Hello world."
.codePoints()
.mapToObj(c -> c == ' ' ? " ": "*")
.collect(Collectors.joining());
_
Collectors.joining()
は、少なくとも OpenJDKソース でStringBuilder
を内部的に使用します。
他の回答は、文字列のストリームを単一の文字列に収集する方法と、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
は既に使用されています。
必要に応じて、この非常にい方法でワンライナーを作成できます。
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
に配置します。
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()を使用できます
これはどう。
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);
単純な答えがありますが、これはストリーミングですべてを行うことにやや傾いています。したがって、これは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は簡潔と同じではなく、上記の関数がどのように動作するのか不思議に思う人はいないと思います。
このソリューションにより、コードポイントが文字に戻されないことが保証されます。したがって、ここにリストされている他のソリューションよりも多少一般的です。
次のコードで直接行うことができます:-
"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));
できるよ:
_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()));
_