Добавить элемент в каждый список в списке

Допустим, у нас есть следующий базовый список:

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

и входная строка "a"

Я хочу добавить входную строку к каждому списку в списке, в результате чего:

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

Эквивалент Javascript будет:

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

Как этого можно достичь, используя аналогичный идиоматический формат с потоками Java?

если мы получили List<List<String>> base, то base.forEach(l -> l.addFirst("a")); должно подойти (исходные подсписки изменены, addFirst() доступен начиная с Java 21)

user85421 27.07.2024 21:55

Я бы не стал использовать здесь потоковую операцию. Как сказал @user85421. Если еще не на Java 21, с l.add(0, "a").

Anonymous 28.07.2024 08:15

Согласитесь, addFirst или add(0, «a») — хорошие альтернативы, если разумно, что входные данные могут быть изменены. Спасибо за ваши Коментарии.

rph 28.07.2024 14:36

Подумайте о том, можно ли и нужно ли изменить исходный список. Не ждите, что пользователи, отвечающие на вопрос о Java, прочтут ваш код JavaScript или сделают предположения на его основе.

Anonymous 28.07.2024 15:42

Это не было обязательным требованием. Поэтому я оценил ваш комментарий и добавил его как вариант. Извините, если это было неясно.

rph 28.07.2024 20:01
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
99
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Идиоматическое решение с использованием потоков Java, которое я нашел для этого, выглядит следующим образом:

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

Хотя он и не такой лаконичный, как Javascript, он выполняет свою работу без большого количества кода. Однако важно отметить, что использование потоков Java требует важного компромисса между краткостью и читабельностью.

Для полноты эквивалентный код без потоков Java будет таким:

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

Обновлено: Основываясь на других ответах и ​​комментариях, если базовый список изменяем, addFirst или add(0, prefix) также можно использовать как очень краткое решение:

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

вр; доктор

В Java 21+:

strings.addFirst( "a" )

В более ранней версии Java:

strings.add( 0, "a" )

List#addFirst

Если вложенные списки можно изменять, в Java 21+ мы можем просто добавить первый элемент.

Сначала несколько примеров данных.

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]]

Затем мы добавляем в начало каждого вложенного списка.

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

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

Кстати, если вы часто вставляете элементы в List, рассмотрите возможность использования LinkedList , а не ArrayList . См. Когда использовать LinkedList вместо ArrayList в Java?.

Секвенированные коллекции

Метод addFirst является частью функции Sequenced Collections.

См. JEP 431. А еще смотрите хорошую презентацию Стюарта Маркса.

Действительно, вы можете захотеть объявить список списков более общего типа — упорядоченной коллекцией упорядоченных коллекций.

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

Мой предпочтительный ответ. Если еще нет в Java 21, можно использовать strings.add( 0, "a" ).

Anonymous 28.07.2024 08:12

Используя потоки Java, вы можете добиться этого, как показано ниже.

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

Ваш результат — это желаемый список здесь.

Другие вопросы по теме