Effectively combine text in nested lists

Suppose I have text presented as a set of lines of words. I want to combine the words in a line with a space and connect the lines with a new line:

class Word { String value; } public static String toString(List <List <Word>> lines) { return lines.stream().map( l -> l.stream().map(w -> w.value).collect(Collectors.joining(" ")) ).collect(Collectors.joining("\n")); } 

This works fine, but in the end I create an intermediate String object for each line. Is there a nice concise way to do the same without the overhead?

+5
source share
2 answers

you can use

 public static String toString(List<List<Word>> lines) { return lines.stream() .map(l -> l.stream() .map(w -> w.value) .collect(() -> new StringJoiner(" "), StringJoiner::add, StringJoiner::merge)) .collect(() -> new StringJoiner("\n"), StringJoiner::merge, StringJoiner::merge).toString(); } 

The internal collect basically does what Collectors.joining(" ") does, but skips the final step of StringJoiner.toString() .

Then the external collect is different from the usual Collectors.joining("\n") in that it accepts StringJoiner as input and combines them with merge . It depends on the documented behavior :

If another StringJoiner uses a different separator, then elements from another StringJoiner are combined with this separator, and the result is added to this StringJoiner as one element.

This is done internally at the StringBuilder / character data level without instantiating a String while preserving the intended semantics.

+3
source
  String s = List.of( List.of(new Word("a"), new Word("b")), List.of(new Word("c"), new Word("d")), List.of(new Word("e"), new Word("f"))) .stream() .collect(Collector.of( () -> new StringJoiner(""), (sj, list) -> { list.forEach(x -> sj.add(x.getValue()).add(" ")); sj.add("\n"); }, StringJoiner::merge, StringJoiner::toString)); 

EDIT

I can do this, but I can’t say whether you agree to the additional verbosity and the creation of this line:

 .stream() .collect(Collector.of( () -> new StringJoiner(""), (sj, list) -> { int i; for (i = 0; i < list.size() - 1; ++i) { sj.add(list.get(i).getValue()).add(" "); } sj.add(list.get(i).getValue()); sj.add("\n"); }, StringJoiner::merge, x -> { String ss = x.toString(); return ss.substring(0, ss.length() - 1); })); 
+5
source

Source: https://habr.com/ru/post/1275225/


All Articles