Simplest way to print an `IntStream` as a `String`

十年热恋 提交于 2019-12-28 02:49:26

问题


With Java-8 I can easily treat a String (or any CharSequence) as an IntStream using either the chars or the codePoints method.

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

I can then manipulate the contents of the stream

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

I have been hunting for a tidy way to print the results and I cant even find a simple way. How do I put this stream of ints back into a form that can be printed like I can a String.

From the above stars I hope to print

***** ******

回答1:


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

But still, "Hello world.".replaceAll("[^ ]", "*") is simpler. Not everything benefits from lambdas.




回答2:


A bit less efficient but more concise solution to Holger's:

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

Collectors.joining() internally uses StringBuilder, at least in OpenJDK sources.




回答3:


Other answers show how to collect a stream of strings into a single string and how to collect characters from an IntStream. This answer shows how to use a custom collector on a stream of characters.

If you want to collect a stream of ints into a string, I think the cleanest and most general solution is to create a static utility method that returns a collector. Then you can use the Stream.collect method as usual.

This utility can be implemented and used like this:

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);
}

It's a bit surprising that there isn't something like this in the standard library.

One disadvantage of this approach is that it requires the chars to be boxed since the IntStream interface does not work with collectors.

An unsolved and hard problem is what the utility method should be named. The convention for collector utility methods is to call them toXXX, but toString is already taken.




回答4:


If we must, we can make a one-liner this extremely ugly way:

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

It performs the exact same version as my other answer but it uses streaming all the way. Some function to convert a single code point to a string is obviously needed:

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);
}

which places these functions in the class Stars of course.




回答5:


The way I do it is by using reduce. To get * for each character and space for each space it will look like this

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

The point is do whatever you want with the integers than cast it to characters then map it to String then concatenate it, you can use reduce or Collectors.joining()




回答6:


You can do it directly with the following code :-

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



回答7:


There is a simple answer that is slightly less inclined to doing everything with streaming. Hence it is not a one-liner, but it is probably more efficient and very easy to read:

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

Sometimes short is not the same as concise, I don't think anybody has to wonder how the above function operates.

This solution makes sure that the code points are never converted back to characters. It is therefore somewhat more generic than some other solutions listed here.




回答8:


How about this.

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



回答9:


You can do:

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

Another example:

The following examples return the original string. But these can be combined with other intermediate operations such as filter().

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

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


来源:https://stackoverflow.com/questions/20266422/simplest-way-to-print-an-intstream-as-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!