-1

This is how my map looks like.

Map<String, String> maps = List.stream().collect(Collectors.toMap(Cat::getName, Cat::getNumber, (c1,c2) -> c1));

If I already have "Lucy, 101" in maps then I am unable to add another value corresponding to the name Lucy i.e "Lucy, 102". Is there any way to change the merge function [ (c1,c2) -> c1 ] so that I can have two values corresponding to a single key (Lucy) in my maps?

Meg
  • 88
  • 1
  • 8
  • 5
    So if you do `maps.get("Lucy")`, which one would you expect to get? How about changing `maps` to a `Map>` (in which case you'd use `groupingBy`)? – Sweeper Jun 06 '21 at 10:08
  • @Sweeper I want both the values to my key. Eg. maps.get("Lucy") should return both 101 and 102. Is there any way to store both the values without changing `maps` to a `Map, List> ?` – Meg Jun 06 '21 at 10:11
  • Would you accept joining the strings together (`"101 102"`) as "both 101 and 102"? – Sweeper Jun 06 '21 at 10:27
  • I was thinking of joining the strings only if I have no other options left – Meg Jun 06 '21 at 10:30

2 Answers2

4

By your requirement, in order to allow multiple values for the same key, you need to implement the result as Map<String, Collection<String>>.

In your case, you can merely use groupingBy + mapping collectors instead of toMap with the merge function:

Map<String, List<String>> maps = List.stream()
        .collect(Collectors.groupingBy(
            Cat::getName, 
            Collectors.mapping(Cat::getNumber, Collectors.toList())
        );

However, you may want to consider a merge function as joining strings:

Map<String, String> maps = List.stream()
        .collect(Collectors.toMap(
            Cat::getName, 
            Cat::getNumber, (num1, num2) -> String.join("; ", num1, num2)
        );

Then the map would contain "compound" values in the form of a string.

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
2

Since the type of your map is Map<String, String>, it can only return one string. However, you expect to get multiple strings from get. You need to change the type of the map to e.g. Map<String, List<String>> or Map<String, Collection<String>>.

Then, you can use groupingBy like this:

Map<String, List<String>> map = yourList.stream().collect(Collectors.groupingBy(
    Cat::getName, // group by the name
    Collectors.mapping( // map each group of cats to their numbers
        Cat::getNumber, Collectors.toList() // collect each group to a list
    )
));

If you are okay with multiple numbers in the same string (e.g. "101 102"), you can use Collectors.joining:

Map<String, String> map = yourList.stream().collect(Collectors.groupingBy(
    Cat::getName,
    Collectors.mapping(
        Cat::getNumber, Collectors.joining(" ")
    )
));
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Okay. What if we don't look at the scenario of getting multiple Strings from `get`? I just want to store multiple values to a key. Is that possible? – Meg Jun 06 '21 at 10:28
  • @Meg What is the point of that, if you can't get it with `get`? Do you just want `values` to contain it? – Sweeper Jun 06 '21 at 10:31
  • And why don't you want to change the type of `maps`? This is beginning to sound like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) to be honest. @Meg – Sweeper Jun 06 '21 at 10:33
  • yeah, that's true. Anyways, thank you for your help :) – Meg Jun 06 '21 at 10:36