问题
I have a list of maps.
List<Map<Integer, String>>
The values in the list are, for example
<1, String1>
<2, String2>
<1, String3>
<2, String4>
As an end result, I want a Map>, like
<1, <String1, String3>>
<2, <String2, String4>>
How can I achieve this in Java.
CODE :
List<Map<Integer, String>> genericList = new ArrayList<Map<Integer,String>>();
for(TrackActivity activity : activityMajor){
Map<Integer, String> mapIdResponse = activity.getMapIdResponse();
genericList.add(mapIdResponse);
}
Now this genericList is the input and from this list, based on the same ids I want a
Map<Integer, List<String>> mapIdResponseList
Basically, to club the responses which are String based on the ids, grouping the responses with same id in a list and then creating a new map with that id as the key and the list as its value.
回答1:
You can do it the following with Java 8:
private void init() {
List<Map<Integer, String>> mapList = new ArrayList<>();
Map<Integer, String> map1 = new HashMap<>();
map1.put(1, "String1");
mapList.add(map1);
Map<Integer, String> map2 = new HashMap<>();
map2.put(2, "String2");
mapList.add(map2);
Map<Integer, String> map3 = new HashMap<>();
map3.put(1, "String3");
mapList.add(map3);
Map<Integer, String> map4 = new HashMap<>();
map4.put(2, "String4");
mapList.add(map4);
Map<Integer, List<String>> response = mapList.stream()
.flatMap(map -> map.entrySet().stream())
.collect(
Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(
Map.Entry::getValue,
Collectors.toList()
)
)
);
response.forEach((i, l) -> {
System.out.println("Integer: " + i + " / List: " + l);
});
}
This will print:
Integer: 1 / List: [String1, String3]
Integer: 2 / List: [String2, String4]
Explanation (heavily warranted), I am afraid I cannot explain every single detail, you need to understand the basics of the Stream and Collectors API introduced in Java 8 first:
- Obtain a
Stream<Map<Integer, String>>from themapList. - Apply the
flatMapoperator, which roughly maps a stream into an already existing stream.
Here: I convert allMap<Integer, String>toStream<Map.Entry<Integer, String>>and add them to the existing stream, thus now it is also of typeStream<Map.Entry<Integer, String>>. - I intend to collect the
Stream<Map.Entry<Integer, String>>into aMap<Integer, List<String>>. - For this I will use a
Collectors.groupingBy, which produces aMap<K, List<V>>based on a grouping function, aFunctionthat maps theMap.Entry<Integer, String>to anIntegerin this case. - For this I use a method reference, which exactly does what I want, namely
Map.Entry::getKey, it operates on aMap.Entryand returns anInteger. - At this point I would have had a
Map<Integer, List<Map.Entry<Integer, String>>>if I had not done any extra processing. - To ensure that I get the correct signature, I must add a downstream to the
Collectors.groupingBy, which has to provide a collector. - For this downstream I use a collector that maps my
Map.Entryentries to theirStringvalues via the referenceMap.Entry::getValue. - I also need to specify how they are being collected, which is just a
Collectors.toList()here, as I want to add them to a list. - And this is how we get a
Map<Integer, List,String>>.
回答2:
Have a look at guavas MultiMap. Should be exactly what you are looking for:
http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap
来源:https://stackoverflow.com/questions/22527149/create-a-map-from-a-list-of-maps