我有一个项目列表,其中每个项目都可以属于一个或多个类别。对于一组有限的category(string),我想创建一个类别为键的Items列表为值的map。
假设我的Item类的定义如下所示:
public static class Item{
long id;
List<String> belongsToCategories;
public List<String> getBelongsToCategories() {
return belongsToCategories;
}
public void setBelongsToCategories(List<String> belongsToCategories) {
this.belongsToCategories = belongsToCategories;
}
public Item(long id,List<String> belongsToCategories) {
this.id = id;
this.belongsToCategories = belongsToCategories;
}
@Override
public String toString() {
return "Item{" + "id=" + id + '}';
}
}
和项目列表:
public static void main(String[] args) {
List<Item> myItemList = new ArrayList<>();
myItemList.add(new Item(1,Arrays.asList("A","B")));
myItemList.add(new Item(2,Arrays.asList("A","C")));
myItemList.add(new Item(3,Arrays.asList("B","C")));
myItemList.add(new Item(4,Arrays.asList("D")));
myItemList.add(new Item(5,Arrays.asList("D","E")));
myItemList.add(new Item(6,Arrays.asList("A","F")));
Map<String,List<Item>> myMap= new HashMap<>();
如何从myList填充myMap?
我认为Stream API可以提供帮助,但是当某项可以属于一个或多个类别时,我不知道将哪个分类器放入groupingBy方法中
myItemList.stream().collect(Collectors.groupingBy(classifier));
此
myItemList.stream().collect(Collectors.groupingBy(Item::getBelongsToCategories));
产生
[D, E]=[Item{id=5}]
[B, C]=[Item{id=3}]
[A, B]=[Item{id=1}]
[D]=[Item{id=4}]
[A, C]=[Item{id=2}]
[A, F]=[Item{id=6}]
预期很难,例如:
A=[Item{id=1}, Item{id=2}, Item{id=6}]
B=[Item{id=1}, Item{id=3}]
C=[Item{id=2}, Item{id=3}]
D=[Item{id=4}, Item{id=5}]
E=[Item{id=5}]
F=[Item{id=6}]
答案 0 :(得分:3)
您可以使用Eclipse Collections中的groupByEach
。
Multimap<String, Item> itemsByCategory =
ListIterate.groupByEach(myItemList, Item::getBelongsToCategories);
System.out.println(itemsByCategory);
输出:
{D=[Item{id=4}, Item{id=5}],
E=[Item{id=5}],
F=[Item{id=6}],
A=[Item{id=1}, Item{id=2}, Item{id=6}],
B=[Item{id=1}, Item{id=3}],
C=[Item{id=2}, Item{id=3}]}
您还可以将Collectors2
实用程序类和groupByEach
收集器与Java Stream
一起使用。
Multimap<String, Item> itemsByCategory = myItemList.stream().collect(
Collectors2.groupByEach(
Item::getBelongsToCategories,
Multimaps.mutable.list::empty));
注意:我是Eclipse Collections的提交者。
答案 1 :(得分:2)
您可以使用flatMap
映射到SimpleEntry
,然后将groupingBy
映射为:
return items.stream()
.flatMap(p -> p.getBelongsToCategories()
.stream()
.map(l -> new AbstractMap.SimpleEntry<>(l, p)))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));
答案 2 :(得分:1)
这是ListMultimap
的解决方案,来自Google Guava或我的图书馆Abacus-Util
ListMultimap<String, Item> result = Multimaps.newListMultimap(new HashMap<>(), () -> new ArrayList<>()); // by Google Guava.
// Or result = N.newListMultimap(); // By Abacus-Util
items.forEach(item -> item.getBelongsToCategories().forEach(c -> result.put(c, item)));
我认为,如果不通过Entry
创建不必要的临时flatMap
对象,它将更加高效和简洁。