0

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?

3
  • 3
    if we got List<List<String>> base, then base.forEach(l -> l.addFirst("a")); should do (original sub-lists are changed, addFirst() available since Java 21) Commented Jul 27, 2024 at 19:55
  • I would not use a stream operation here. Just as @user85421 said. If not yet on Java 21, with l.add(0, "a"). Commented Jul 28, 2024 at 6:15
  • Agree addFirst or add(0, "a") are good alternatives if it's reasonable the input can be mutated. Thank you for your comments. Commented Jul 28, 2024 at 12:36

3 Answers 3

3

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
}
Sign up to request clarification or add additional context in comments.

Comments

3

tl;dr

In Java 21+:

strings.addFirst( "a" )

In earlier Java:

strings.add( 0, "a" )

List#addFirst

If the nested lists are modifiable, in Java 21+ we can simply add first element.

First, some example data.

List < List < String > > listOfListsOfStrings =
        List.of(
                new ArrayList <>( List.of( "Foo" ) ) ,
                new ArrayList <>( List.of( "Bar" ) )
        );
System.out.println( "listOfListsOfStrings = " + listOfListsOfStrings );

listOfListsOfStrings.toString() = [[Foo], [Bar]]

Then we prepend on each nested list.

listOfListsOfStrings.forEach( strings -> strings.addFirst( "a" ) );

listOfListsOfStrings.toString() = [[a, Foo], [a, Bar]]

By the way, if frequently inserting elements into a List, consider using LinkedList rather than ArrayList. See When to use LinkedList over ArrayList in Java?.

Sequenced collections

The addFirst method is part of the Sequenced Collections feature.

See JEP 431. And see also the good presentation by Stuart Marks.

Class hierarchy diagram with sequenced collections, by Stuart Marks of Oracle Corp.

Indeed, you might want to declare your list of lists to be of the more general type, a sequenced collection of sequenced collections.

SequencedCollection < SequencedCollection < String > > seqcolOfSeqcolOfStrings =
        List.of(
                new ArrayList <>( List.of( "Foo" ) ) ,
                new ArrayList <>( List.of( "Bar" ) )
        );
…

1 Comment

My preferred answer. If not yet in Java 21, one may use strings.add( 0, "a" ).
1

Using java streams you can achive this like below

List<List<String>> parentLList = Arrays.asList(
            Arrays.asList("foo"),
            Arrays.asList("bar")
        );

        // Input string to prepend
        String prependString = "a";

        // preprend the input to each list using stream
        List<List<String>> yourResult = parentLList.stream()
            .map(innerList -> {
                List<String> newList = new ArrayList<>();
                newList.add(prependString);
                newList.addAll(innerList);
                return newList;
            })
            .collect(Collectors.toList());

yourResult is your desired list here.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.