bob9123
bob9123

Reputation: 745

How to map to multiple elements and collect

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);

Upvotes: 6

Views: 9990

Answers (3)

Oleksandr Pyrohov
Oleksandr Pyrohov

Reputation: 16216

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();

Upvotes: 0

Eugene
Eugene

Reputation: 120848

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());

Upvotes: 14

Eran
Eran

Reputation: 393771

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);

Upvotes: 1

Related Questions