создание потока List of List (вложенный список) с использованием forEach, Java 8 - PullRequest
0 голосов
/ 14 декабря 2018
class EntityCompositeId {
    private Long firstId;
    private Long secondId;
    // getter & setter...
}

class EntityComposite {
    private EntityCompositeId id;
    private String first;
    private String second;
    // getter & setter...
}

List<EntityComposite> listEntityComposite = ....
Supose this content

1, 1, "firstA", "secondBirdOne"
1, 2, "firstA", "secondBirdTwo"
1, 3, "firstA", "secondBirdThree"

2, 1, "firstB", "secondCatOne"
2, 2, "firstB", "secondCatTwo"
2, 3, "firstB", "secondCatThree"

3, 1, "firstC", "secondDogOne"
3, 2, "firstC", "secondDogTwo"
3, 3, "firstC", "secondDogThree"

Map<Long, List<String>> listOfLists = new HashMap<>();

Теперь используя поток я хочу заполнить как:

 1 -> {"secondBirdOne", "secondBirdTwo", "secondBirdThree"}
 2 -> {"secondCatOne", "secondCatTwo", "secondCatThree"}
 3 -> {"secondDogOne", "secondDogTwo", "secondDogThree"}

Мой НЕЗАКОНЧЕННЫЙ (вот в чем вопрос) код:

listEntityComposite.stream()forEach(entityComposite {
        // How create a list according entityComposite.getId.getFirstId()?
        listOfLists.put(entityComposite.getId.getFirstId(), .... )
    });

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Существует несколько различных подходов, в которых вы можете выполнить задачу под рукой.

forEach + computeIfAbsent

 Map<Long, List<String>> map = new HashMap<>();
 listEntityComposite.forEach(e -> map.computeIfAbsent(e.getId().getFirstId(), 
                k -> new ArrayList<>()).add(e.getSecond()));
  • перечисляет элементы listEntityComposite через forEach
  • , для каждого элемента используется computeIfAbsent для вычисления ключа (т.е. firstId) и значения (например, List<String>)

groupingBy + отображение

другой подход заключается в применении groupingBy с mapping нисходящим коллектором:

Map<Long, List<String>> resultSet = listEntityComposite.stream()
                .collect(groupingBy(e -> e.getId().getFirstId(),
                        mapping(EntityComposite::getSecond, toList())));
  • группирует исходные элементы по функции классификации e.getId().getFirstId() и затем применяет mapping нисходящий коллектор для дальнейшего уточнения нашего запроса.

forEach + merge

listEntityComposite.forEach(e -> map.merge(e.getId().getFirstId(),
                new ArrayList<>(singletonList(e.getSecond())),
                (l, r) -> {l.addAll(r); return l;}));
  • перечисляет элементы в listEntityComposite через forEach

  • для каждого элемента используется mergeвычислить ключ (т.е. firstId) и значение (например, List<String>)

toMap

listEntityComposite.stream()
                   .collect(toMap(e -> e.getId().getFirstId(), 
                             v ->  new ArrayList<>(singletonList(v.getSecond())),
                             (l, r) -> {l.addAll(r); return l;}));
  • применяется keyMapperфункция e -> e.getId().getFirstId() для извлечения ключей карты.
  • применяет valueMapper функцию v -> new ArrayList<>(singletonList(v.getSecond())) для извлечения значений карты.
  • применяет merge функцию (l, r) -> {l.addAll(r); return l;} для разрешения столкновений клавиш.

В заключение, подход forEach + computeIfAbsent и подход groupingBy + mapping - это те два, которые вам следует отдать предпочтение в этом конкретном случае, поскольку они более идиоматичны.

0 голосов
/ 15 декабря 2018

Я бы посоветовал взглянуть на MultiMap в Guava, который упрощает работу с вашим вариантом использования (предоставляя множество оптимизаций и дополнительную функциональность, которую вы, возможно, захотите получить позже)

Редактировать: пример того, почемуMultimap имеет больше смысла, чем, скажем, использование подхода computeIfAbsent: 1. у каждого ключа есть список определенного размера, что если вы захотите получить «общий» размер в будущем?вам нужно было бы создать некоторую логику для достижения этой цели с хорошей производительностью (или использовать метод, который использует O (ключи)) 2. в данный момент вы только помещаете вещи в карту, но что произойдет, если вы хотите удалить вещи изкарта в будущем?Вам нужно будет написать некоторый шаблонный код (который легко ошибиться), чтобы убедиться, что удаление значений не вызывает утечку памяти

Существуют и другие преимущества, которые можно получить при использовании мультикарты, но это всего лишь дваПреимущества, которые легко объяснить.

Редактировать 2: Пример использования вашего ввода:

import java.util.Arrays;
import java.util.List;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;

public class Example {

    public static class EntityCompositeId {
        @Override
        public String toString() {
            return "EntityCompositeId [firstId=" + firstId + ", secondId=" + secondId + "]";
        }

        public EntityCompositeId(Long firstId, Long secondId) {
            super();
            this.firstId = firstId;
            this.secondId = secondId;
        }

        private Long firstId;

        public Long getFirstId() {
            return firstId;
        }

        private Long secondId;
    }

    public static class EntityComposite {
        @Override
        public String toString() {
            return "EntityComposite [id=" + id + ", first=" + first + ", second=" + second + "]";
        }

        public EntityComposite(EntityCompositeId id, String first, String second) {
            super();
            this.id = id;
            this.first = first;
            this.second = second;
        }

        private EntityCompositeId id;

        public EntityCompositeId getId() {
            return id;
        }

        private String first;
        private String second;
    }

    public static void main(String[] args) {
        List<EntityComposite> listEntityComposite = Arrays.asList(
                new EntityComposite(new EntityCompositeId(1l, 1l), "firstA", "secondBirdOne"),
                new EntityComposite(new EntityCompositeId(1l, 2l), "firstA", "secondBirdTwo"),
                new EntityComposite(new EntityCompositeId(1l, 3l), "firstA", "secondBirdThree"),
                new EntityComposite(new EntityCompositeId(2l, 1l), "firstB", "secondCatOne"),
                new EntityComposite(new EntityCompositeId(2l, 2l), "firstB", "secondCatTwo"),
                new EntityComposite(new EntityCompositeId(2l, 3l), "firstB", "secondCatThree"),
                new EntityComposite(new EntityCompositeId(3l, 1l), "firstC", "secondDogOne"),
                new EntityComposite(new EntityCompositeId(3l, 2l), "firstC", "secondDogTwo"),
                new EntityComposite(new EntityCompositeId(3l, 3l), "firstC", "secondDogThree"));
        ListMultimap<Long, EntityComposite> map = ArrayListMultimap.create();
        listEntityComposite.forEach(entityComposite -> map.put(entityComposite.getId().getFirstId(), entityComposite));
        map.keySet().forEach(key -> System.out.println(map.get(key)));
    }
}

Получает следующий вывод:

[EntityComposite [id=EntityCompositeId [firstId=1, secondId=1], first=firstA, second=secondBirdOne], EntityComposite [id=EntityCompositeId [firstId=1, secondId=2], first=firstA, second=secondBirdTwo], EntityComposite [id=EntityCompositeId [firstId=1, secondId=3], first=firstA, second=secondBirdThree]]
[EntityComposite [id=EntityCompositeId [firstId=2, secondId=1], first=firstB, second=secondCatOne], EntityComposite [id=EntityCompositeId [firstId=2, secondId=2], first=firstB, second=secondCatTwo], EntityComposite [id=EntityCompositeId [firstId=2, secondId=3], first=firstB, second=secondCatThree]]
[EntityComposite [id=EntityCompositeId [firstId=3, secondId=1], first=firstC, second=secondDogOne], EntityComposite [id=EntityCompositeId [firstId=3, secondId=2], first=firstC, second=secondDogTwo], EntityComposite [id=EntityCompositeId [firstId=3, secondId=3], first=firstC, second=secondDogThree]]
0 голосов
/ 14 декабря 2018

collect является более подходящей терминальной операцией для генерации выхода Map, чем forEach.

. Вы можете использовать collect() с Collectors.groupingBy:

Map<Long, List<String>> listOfLists =
    listEntityComposite.stream()
                       .collect(Collectors.groupingBy(e -> e.getId().getFirstId(),
                                                      Collectors.mapping(EntityComposite::getSecond,
                                                                         Collectors.toList());

Collectors.groupingBy с одним аргументом (просто e -> e.getId().getFirstId()) сгенерирует Map<Long,List<EntityComposite>>.

Цепочка к нему Collectors.mapping() сопоставляет каждый экземпляр EntityComposite с соответствующим getSecond() String, как требуется.

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