Search code examples
javajava-streamspread-syntax

Prepend an element to each list in a list


Let's say we have the following base list:

[["foo"],["bar"]]

and the input string "a"

I want to prepend the input string to each list in the list, which results in:

[["a", "foo"], ["a", "bar"]]

The Javascript equivalent would be:

const base = [["foo"], ["bar"]]
const prefix = "a"
const prefixedBase = base.map(it => [prefix, ...it])

How can this be achieved using a similar idiomatic format with Java streams?


Solution

  • The idiomatic solution using Java streams I found for this is as follows:

    var base = List.of(List.of("foo"), List.of("bar"));
    var prefix = "a";
    var prefixedBase = base.stream()
            .map(it -> Stream.concat(Stream.of(prefix), it.stream()).toList())
            .toList();
    

    While not as concise as Javascript, it does the job without much code. However, it's important to note that using Java streams requires an important trade-off between conciseness and readability.

    For the sake of completeness, the equivalent code without Java streams would be:

    var base = List.of(List.of("foo"), List.of("bar"));
    var prefix = "a";
    var prefixedBase = new ArrayList<List<String>>();
    for (var subList: base) {
        var newSubList = new ArrayList<String>();
        newSubList.add(prefix);
        newSubList.addAll(subList);
        prefixedBase.add(newSubList);
    }
    

    EDIT: Based on other answers and comments, if the base list is mutable, addFirst or add(0, prefix) can also be used as a very concise solution:

    for (var subList: base) {
        subList.addFirst(prefix); // add(0, prefix) before Java 21
    }