I have a list of Items where each Item can belong to one or more category. For a limited set of categories(string) I want to create a map with category as key and list of Items as value.
Assume my Item class is defined as shown below:
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 + '}';
}
}
and a list of Items:
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<>();
How can i fill myMap from myList?
I thought Stream API could help, but I don't know which classifier to put in the groupingBy method when an Item can belong to one or more categories
myItemList.stream().collect(Collectors.groupingBy(classifier));
This
myItemList.stream().collect(Collectors.groupingBy(Item::getBelongsToCategories));
produces
[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}]
expected is tough something like:
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}]
You can use flatMap
to map to SimpleEntry
and then groupingBy
as :
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())));
You can use groupByEach
from Eclipse Collections.
Multimap<String, Item> itemsByCategory =
ListIterate.groupByEach(myItemList, Item::getBelongsToCategories);
System.out.println(itemsByCategory);
Output:
{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}]}
You can also use the Collectors2
utility class and groupByEach
Collector with a Java Stream
.
Multimap<String, Item> itemsByCategory = myItemList.stream().collect(
Collectors2.groupByEach(
Item::getBelongsToCategories,
Multimaps.mutable.list::empty));
Note: I am a committer for Eclipse Collections.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With