I have a List<Set<Integer>>
and want a Map<Integer, List<Set<Integer>>>
which will map each Integer
to all sets
containing that Integer
.
The obvious candidate here would be to use Collectors.groupingBy
but it doesn't work because groupingBy
only allows a classifier function that returns one key. I would need to return several keys for each Set
.
List<Set<Integer>> setList ...;
Map<Integer, List<Set<Integer>>> setMap = setList.stream().collect(
groupingBy(eachSet -> ))
Here is one example of what I want to achieve without using streams:
List<Set<Integer>> setList ...
System.out.print("setList: ");
System.out.println(setList);
Map<Integer, List<Set<Integer>>> setMap = new HashMap<>();
for(Set<Integer> eachSet: setList) {
for(Integer i: eachSet) {
List<Set<Integer>> newSetList = setMap.getOrDefault(i, new ArrayList<>());
newSetList.add(eachSet);
setMap.putIfAbsent(i, newSetList);
}
}
System.out.print("setMap: ");
System.out.println(setMap);
This will output the following:
setList: [[1], [1], [1, 3], [2, 3, 7]]
setMap: {1=[[1], [1], [1, 3]], 2=[[2, 3, 7]], 3=[[1, 3], [2, 3, 7]], 7=[[2, 3, 7]]}
Two approaches:
Make a stream of all integers in all sets, then associate an integer with all sets which contain it.
Map<Integer, List<Set<Integer>>> m1 =
list.stream().flatMap(Set::stream)
.distinct()
.collect(
Collectors.toMap(a -> a,
b -> list.stream().filter(set -> set.contains(b)).collect(Collectors.toList()))
);
Create an intermediate maps which map the elements of the set to itself, then merge those entries into the final map.
Map<Integer, List<Set<Integer>>> m2 = list.stream()
.map(x -> x.stream().collect(Collectors.toMap(a -> a, b -> x)))
.flatMap(x -> x.entrySet().stream())
.collect(
Collectors.toMap(Map.Entry::getKey,
a -> List.of(a.getValue()), (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList()))
);
Note that your for
loop variant is unnecessarily complicated. Instead of getOrDefault
plus putIfAbsent
, you can use a single computeIfAbsent
:
for(Set<Integer> eachSet: setList) {
for(Integer i: eachSet) {
List<Set<Integer>> setList = setMap.computeIfAbsent(i, key -> new ArrayList<>());
setList.add(eachSet);
}
}
which allows a simplification to a chained operation:
for(Set<Integer> eachSet: setList) {
for(Integer i: eachSet) {
setMap.computeIfAbsent(i, key -> new ArrayList<>()).add(eachSet);
}
}
An equivalent Stream operation would be:
Map<Integer, List<Set<Integer>>> setMap = setList.stream()
.flatMap(set -> set.stream().map(i -> new AbstractMap.SimpleImmutableEntry<>(i, set)))
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
Just do the nested iteration using forEach
:
List<Set<Integer>> setList = ...;
Map<Integer, List<Set<Integer>>> setMap = new HashMap<>();
setList.stream().forEach(val -> { //set<Integer>
val.stream().forEach(i -> { //Integer
List<Set<Integer>> newSetList = setMap.getOrDefault(i, new ArrayList<>());
newSetList.add(val);
setMap.putIfAbsent(i, newSetList);
});
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.