Подтвердить что ты не робот

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

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

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

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

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

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

Из вышеприведенного stars я надеюсь напечатать

***** ******
4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

Другие ответы показывают, как собирать поток строк в одну строку и как собирать символы из IntStream. Этот ответ показывает, как использовать пользовательский коллекционер в потоке символов.

Если вы хотите собрать поток ints в строку, я думаю, что самым чистым и наиболее общим решением является создание статического утилитарного метода, который возвращает коллекционер. Затем вы можете использовать метод 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 уже выполнено.

Ответ 4

Если нужно, мы можем сделать однострочный обход очень уродливым:

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, конечно.

Ответ 5

То, как я это делаю, - это использование метода Reduce Чтобы получить * для каждого символа и пробел для каждого пробела, он будет выглядеть следующим образом

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

Суть в том, чтобы делать с целыми числами все, что угодно, чем приводить их к символам, затем сопоставлять их со строками, затем объединять, вы можете использовать Redu или Collectors.joining().

Ответ 6

Вы можете сделать это непосредственно со следующим кодом: -

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

Ответ 7

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

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

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

Это решение гарантирует, что кодовые точки никогда не будут преобразованы обратно в символы. Поэтому он несколько более общий, чем некоторые другие решения, перечисленные здесь.

Ответ 8

Как насчет этого?

  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

Вы можете сделать:

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