How to map to multiple elements and collect
Asked Answered
F

3

6
final List<Toy> toys = Arrays.asList("new Toy(1)", "new Toy(2)"); 

final List<Item> itemList = toys.stream()
   .map(toy -> {
        return Item.from(toy); //Creates Item type
   }).collect(Collectors.toList);

This above codes work fines and will make a list of Items from the list of Toys.

What I want to do is something like this:

final List<Item> itemList = toys.stream()
   .map(toy -> {
        Item item1 = Item.from(toy);
        Item item2 = Item.fromOther(toy);

        List<Item> newItems = Arrays.asList(item1, item2);
        return newItems;
   }).collect(Collectors.toList);

OR

final List<Item> itemList = toys.stream()
   .map(toy -> {
        return Item item1 = Item.from(toy); 
        return Item item2 = Item.fromOther(toy); //Two returns don't make sense but just want to illustrate the idea.       
   }).collect(Collectors.toList);

So comparing this to the first code, the first approach returns 1 Item object for every Toy Object.

How do i make it so I can return a two Item Objects for every Toy?

--UPDATE--

final List<Item> itemList = toys.stream()
   .map(toy -> {
        Item item1 = Item.from(toy);
        Item item2 = Item.fromOther(toy);

        return Arrays.asList(item1,item2);
   }).collect(ArrayList<Item>::new, ArrayList::addAll,ArrayList::addAll);
Freespoken answered 22/5, 2017 at 12:56 Comment(3)
If you have found a solution, don’t update your question with the solution. Accept the relevant answer instead.Studley
I haven't found the solutionFreespoken
@Freespoken that updated post does not say much. what is BasicRule and how do you map and why do you need to provide that explicitly? A minimal runnable example would helpFourierism
F
14

You are already doing that... you just need to flatMap

final List<Item> itemList = toys.stream()
.map(toy -> Arrays.asList(Item.from(toy),Item.fromOther(toy))
.flatMap(List::stream)
.collect(Collectors.toList());

Or you drop the mapping entirely as suggested:

final List<Item> itemList = toys.stream()
.flatMap(toy -> Stream.of(Item.from(toy),Item.fromOther(toy))))
.collect(Collectors.toList());
Fourierism answered 22/5, 2017 at 13:0 Comment(0)
W
1

If you wish to return two Items for each Toy, perhaps the output type should be a List<List<Item>>:

List<List<Item>> itemList = 
    toys.stream()
        .map(toy -> Arrays.asList(Item.from(toy),Item.fromOther(toy)))
        .collect(Collectors.toList);

If you wish the two Items per Toy to be collected into the same List<Item>, use flatMap:

List<Item> itemList = 
    toys.stream()
        .flatMap(toy -> Stream.of(Item.from(toy),Item.fromOther(toy)))
        .collect(Collectors.toList);
Winifredwinikka answered 22/5, 2017 at 13:1 Comment(2)
I would rather have it to be one List but contain two elementsFreespoken
@Freespoken In that case, you should use flatMap instead of map. See edit.Winifredwinikka
P
0

For future readers who stumbled across the same question, there was this new fancy method added starting from Java-16 - mapMulti - it does exactly what is asked in the question and it doesn't create a new stream comparing to flatMap:

List<Item> itemList =
    toys.stream()
        .mapMulti(
            (Toy toy, Consumer<Item> consumer) -> {
              consumer.accept(Item.from(toy));
              consumer.accept(Item.fromOther(toy));
            })
        .toList();
Probably answered 6/8, 2023 at 21:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.