Reputation: 63
Reading "Java 8 In Action" I created real life excercise to put object for example in message queue:
I have an Object that has a List inside. I would like to group a List of those objects with streams by elements from objects List. I need Map or at least List, see example.
Example:
Beverage cola = new Beverage("Cola", Arrays.asList("cubes", "lemon"));
Beverage tea = new Beverage("Tea", Arrays.asList("sugar", "milk", "lemon"));
class Beverage{
String name;
List<String> adds;
public Beverage(String name, List<String> adds) {
this.name = name;
this.adds = adds;
}
public String getName() {
return name;
}
public List<String> getAdds() {
return adds;
}
@Override
public String toString() {
return "Beverage{" +
"name='" + name + '\'' +
", adds=" + adds +
'}';
}
}
I have this:
final Map<List<String>, Beverage> collect = beveragesMenu.stream()
.collect(Collectors.toMap(Beverage::getAdds, beverage -> beverage));
and it produces:
Key: [cubes, lemon]: Beverage{name='Cola', adds=[cubes, lemon]}
Key: [sugar, milk, lemon]: Beverage{name='Tea', adds=[sugar, milk, lemon]}
but I need Map:
Key: [cubes]: Beverage{name='Cola', adds=[cubes, lemon]}
Key: [sugar,]: Beverage{name='Tea', adds=[sugar, milk, lemon]}
Key: [milk]: Beverage{name='Tea', adds=[sugar, milk, lemon]}
Key: [lemon]: Beverage{name='Tea', adds=[sugar, milk, lemon]},Beverage{name='Cola', adds=[cubes, lemon]}
or/and List:
Beverage{name='Cola', adds=[cubes]}
Beverage{name='Cola', adds=[lemon]}
Beverage{name='Tea', adds=[sugar]}
Beverage{name='Tea', adds=[milk]}
Beverage{name='Tea', adds=[lemon]}
Upvotes: 1
Views: 202
Reputation: 16508
Assuming you have a list of beverages like:
List<Beverage> myBeverageList = List.of(new Beverage("Cola", Arrays.asList("cubes", "lemon")),
new Beverage("Tea", Arrays.asList("sugar", "milk", "lemon"))
);
you can generate a ingredients-to-list-of-beverage mapping:
Map<String, List<Beverage>> ingredientsToBeverageMapping = myBeverageList.stream()
.flatMap(bev -> bev.getAdds().stream()
.map(ingr -> new AbstractMap.SimpleEntry<>(ingr, bev)))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
Upvotes: 1
Reputation: 1829
You can do something like this. Basically for each "add", a map is created, then the each entry of the map is put to the list. You can create new Beverage
objects from them as well.
public static void main(String[] args) {
Beverage cola = new Beverage("Cola", Arrays.asList("cubes", "lemon"));
Beverage tea = new Beverage("Tea", Arrays.asList("sugar", "milk", "lemon"));
Stream.of(cola, tea)
.map(Main::mapBeverage)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toList())
.forEach(System.out::println);
}
private static Map<String, Beverage> mapBeverage(Beverage beverage) {
return beverage.getAdds()
.stream()
.collect(Collectors.toMap(
add -> add,
add -> beverage
));
}
It outputs:
lemon=Beverage{name='Cola', adds=[cubes, lemon]}
cubes=Beverage{name='Cola', adds=[cubes, lemon]}
lemon=Beverage{name='Tea', adds=[sugar, milk, lemon]}
milk=Beverage{name='Tea', adds=[sugar, milk, lemon]}
sugar=Beverage{name='Tea', adds=[sugar, milk, lemon]}
Upvotes: 1
Reputation: 1086
For something, like this I suggest you go with a flatMap
Code:
public List<Beverage> beverages = Arrays.asList(cola, tea);
beverages.stream()
.flatMap(beverage -> beverage.getAdds().stream().map(add -> new Beverage(beverage.getName(), Collections.singletonList(add))))
.collect(Collectors.toList())
Output:
[
Beverage{name='Cola', adds=[cubes]},
Beverage{name='Cola', adds=[lemon]},
Beverage{name='Tea', adds=[sugar]},
Beverage{name='Tea', adds=[milk]},
Beverage{name='Tea', adds=[lemon]}
]
Upvotes: 1