Сейчас я изучаю поток Java 8, мне любопытно, есть ли какой-нибудь удобный способ преобразовать List<Pair<A,B>>
в List<Pair<A,List<B>>>
, то есть объединить значения пары по ключу?
Я когда-либо думал использовать метод forEach
, но он кажется менее эффективным, так как мне нужно пройти по новому списку, чтобы проверить ключ пары.
Концептуальная структура данных/модель будет более четко описана при использовании Set
и Map
, например: List<Pair<A,B>>
-> Map<A,Set<B>>
. Тогда мы знаем, что выходные ключи (A) должны быть уникальными, а значения (B) в каждом ключе должны быть уникальными (однако ни Map/Set не гарантируют порядок по умолчанию). Это также указывает на потенциальное использование HashMap и HashSet в качестве реализаций для относительно эффективной обработки операции. если порядок не имеет значения.
@user2864740 user2864740 вы правы, но, учитывая, что могут быть значения, упорядоченные по ключу A, я не хочу его нарушать.
Я бы предложил использовать LinkedHashMap
(который также поддерживает порядок вставки записей) вместо List<Pair<>>
. Используя это, вы можете просто использовать Collectors.groupingBy()
и Collectors.mapping()
для достижения этого:
List<Pair<A, B>> list = ...;
Map<A, List<B>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toList())));
Однако, если вам действительно нужен List<Pair<>>
, вы можете преобразовать карту обратно в это:
List<Pair<A, B>> list = ...;
List<Pair<A, List<B>>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toList())))
.entrySet().stream()
.map(e -> new Pair<>(e.getKey(), e.getValue()))
.collect(Collectors.toList());
Имейте в виду, что вы повторяете дважды с этим решением (сначала список, затем карта).
Кроме того, если вы также хотите удалить дубликаты B
, вы можете использовать для этого LinkedHashSet
(который также сохраняет порядок). Для этого вам просто нужно изменить отображение нижестоящего коллектора:
List<Pair<A, B>> list = ...;
Map<A, Set<B>> result = list.stream()
.collect(Collectors.groupingBy(Pair::getKey, LinkedHashMap::new,
Collectors.mapping(Pair::getValue, Collectors.toCollection(LinkedHashSet::new))));
Мне любопытно, если я просто использую linkedHashMap после вызова linkedHashMap.steam().collector(Collectors.toMap()), сохранится ли порядок?
@WilliamZ, если вы используете LinkedHashMap::new
в качестве поставщика mapFactory, да, если нет, то нет. Если вы не предоставляете mapFactory, используется HashMap
(неупорядоченный).
b/c Мне нужно просмотреть новый список Pair<A, List<B>> и найти повторяющийся ключ A каждой пары, а затем вставить соответствующее значение в список<B>