MiR
MiR

Reputation: 63

I would like to make a list or map by list inside object using java streams

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

Answers (3)

Eritrean
Eritrean

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

Mansur
Mansur

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

Anurag Wagh
Anurag Wagh

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

Related Questions