web-dev-qa-db-fra.com

Le moyen le plus simple d’imprimer un `IntStream` en tant que` String`

Avec Java-8, je peux facilement traiter une String (ou toute CharSequence) comme une IntStream en utilisant la méthode chars ou la méthode codePoints.

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

Je peux alors manipuler le contenu du flux

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

J'ai été à la recherche d'un moyen ordonné d'imprimer les résultats et je ne peux même pas trouver un moyen simple. Comment puis-je mettre ce flux de ints dans un formulaire qui peut être imprimé comme je peux un String.

De ce qui précède stars j'espère imprimer

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

Mais quand même, "Hello world.".replaceAll("[^ ]", "*") est plus simple. Les lambdas ne sont pas tous bénéfiques.

31
Holger

Solution un peu moins efficace mais plus concise que celle de Holger:

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

Collectors.joining() utilise en interne StringBuilder, au moins dans sources OpenJDK .

18
Lukasz Wiktor

D'autres réponses montrent comment collecter un flux de chaînes en une seule chaîne et collecter des caractères à partir d'une IntStream. Cette réponse montre comment utiliser un collecteur personnalisé sur un flux de caractères.

Si vous souhaitez collecter un flux d'ints dans une chaîne, je pense que la solution la plus propre et la plus générale consiste à créer une méthode d'utilitaire statique qui Renvoie un collecteur. Ensuite, vous pouvez utiliser la méthode Stream.collect comme d'habitude. 

Cet utilitaire peut être implémenté et utilisé comme ceci:

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

Il est un peu étonnant que la bibliothèque standard n’ait rien de tel.

Un inconvénient de cette approche est qu’elle nécessite que les caractères soient encadrés car l’interface IntStream ne fonctionne pas avec les collecteurs.

Un problème non résolu et difficile est ce que la méthode utilitaire doit être nommée. La convention pour les méthodes de l'utilitaire de collecte consiste à les appeler toXXX, mais toString est déjà utilisé.

6
Lii

Si nous devons, nous pouvons faire un one-liner de cette manière extrêmement laide:

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

Il exécute exactement la même version que mon autre réponse mais utilise la diffusion en continu. Certaines fonctions pour convertir un seul point de code en chaîne sont évidemment nécessaires:

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

qui place ces fonctions dans la classe Stars bien sûr.

1
Maarten Bodewes

Il existe une réponse simple qui est légèrement moins encline à tout faire en streaming. Ce n’est donc pas un one-liner, mais c’est probablement plus efficace et très facile à lire:

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

Parfois, court n'est pas synonyme de concis, je ne pense pas que quiconque doive se demander comment fonctionne la fonction ci-dessus.

Cette solution garantit que les points de code ne sont jamais reconvertis en caractères. C'est donc un peu plus générique que certaines des solutions énumérées ici.

0
Maarten Bodewes

Vous pouvez le faire directement avec le code suivant: -

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

Tu peux faire:

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

Un autre exemple:

Les exemples suivants renvoient la chaîne d'origine. Mais ceux-ci peuvent être combinés avec d'autres opérations intermédiaires telles que filter()

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

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