it-swarm.com.ru

Самый простой способ напечатать `IntStream` как` String`

С Java-8 я могу легко обрабатывать String (или любую CharSequence) как IntStream, используя метод chars или codePoints.

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

Затем я могу манипулировать содержимым потока

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

Я искал аккуратный способ напечатать результаты, и я даже не могу найти простой способ. Как мне поместить этот поток ints обратно в форму, которую можно напечатать, как я могу String.

Из вышеизложенного stars Я надеюсь напечатать

***** ******
37
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("[^ ]", "*") проще. Не все выгоды от лямбды.

31
Holger

Немного менее эффективное, но более краткое решение Хольгера:

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

Collectors.joining() внутренне использует StringBuilder, по крайней мере, в исходники OpenJDK .

18
Lukasz Wiktor

Другие ответы показывают, как собрать поток строк в одну строку и как собрать символы из переменной 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 уже занята.

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

Он выполняет ту же версию, что и мой другой ответ но использует потоковую передачу полностью. Очевидно, что нужна некоторая функция для преобразования одной кодовой точки в строку:

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

Есть простой ответ, который чуть менее склонен делать все с потоковым. Следовательно, это не однострочник, но он, вероятно, более эффективен и очень легко читается:

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
Gayan Weerakutti