I have a list of String
.
I want to store each string as key and the string's length as value in a Map
(say HashMap
).
I'm not able to achieve it.
List<String> ls = Arrays.asList("James", "Sam", "Scot", "Elich");
Map<String,Integer> map = new HashMap<>();
Function<String, Map<String, Integer>> fs = new Function<>() {
@Override
public Map<String, Integer> apply(String s) {
map.put(s,s.length());
return map;
}
};
Map<String, Integer> nmap = ls
.stream()
.map(fs).
.collect(Collectors.toMap()); //Lost here
System.out.println(nmap);
All strings are unique.
CodePudding user response:
There's no need to wrap each and every string with its own map, as the function you've created does.
Instead, you need to provide proper arguments while calling Collectors.toMap()
:
keyMapper
- a function responsible for extracting a key from the stream element.valueMapper
- a function that generates a value from the stream element.
Hence, you need the stream element itself to be a key we can use Function.identity()
, which is more descriptive than lambda str -> str
, but does precisely the same.
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // extracting a key
String::length // extracting a value
));
In case when the source list might contain duplicates, you need to provide the third argument - mergeFunction that will be responsible for resolving duplicates.
Map<String,Integer> lengthByStr = ls.stream()
.collect(Collectors.toMap(
Function.identity(), // key
String::length, // value
(left, right) -> left // resolving duplicates
));
CodePudding user response:
You said there would be no duplicate Strings. But if one gets by you can use distinct()
to ensure it doesn't cause issues.
a-> a
is a shorthand for using the stream value. Essentially a lambda that returns its argument.distinct()
removes any duplicate strings
Map<String, Integer> result = names.stream().distinct()
.collect(Collectors.toMap(a -> a, String::length));
The other alternative for handling duplicates is in Alexander Ivanchenko's second toMap
answer.
If you want to get the length of a String
, you can do it immediately as someString.length()
. But suppose you want to get a map of all the Strings keyed by a particular length. You can do it using Collectors.groupingBy()
which by default puts duplicates in a list. In this case, the duplicate would be the length of the String.
- use the
length
of the string as a key. - the value will be a
List<String>
to hold all strings that match that length.
List<String> names = List.of("James", "Sam", "Scot",
"Elich", "lucy", "Jennifer","Bob", "Joe", "William");
Map<Integer, List<String>> lengthMap = names.stream()
.distinct()
.collect(Collectors.groupingBy(String::length));
lengthMap.entrySet().forEach(System.out::println);
prints
3=[Sam, Bob, Joe]
4=[Scot, lucy]
5=[James, Elich]
7=[William]
8=[Jennifer]