Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently joining text in nested lists

Suppose I have a text represented as a collection of lines of words. I want to join words in a line with a space, and join lines with a newline:

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 I end up creating an intermediate String object for each line. Is there a nice concise way of doing the same without the overhead?

like image 208
ykaganovich Avatar asked Feb 07 '18 20:02

ykaganovich


1 Answers

 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 thing of this, but can't tell if you would agree for the extra verbosity vs creating that String:

.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);
          }));
like image 179
Eugene Avatar answered Oct 19 '22 23:10

Eugene