问题
I've just started looking at Java 8 and to try out lambdas, I have an use case for the above problem, which I am solving using the usual for loop which is very lengthy and hard to read
My Existing code
private static Map<DataType, List<OperatorType>> buildmap() {
Map<DataType, List<OperatorType>> map = Maps.newHashMap();
for (OperatorType type : OperatorType.values()) {
List<DataType> supportedTypes = type.getSupportedtypes();
supportedTypes.forEach(datatype -> {
if (map.containsKey(datatype)) {
List<OperatorType> list = map.get(datatype);
list.add(type);
map.put(datatype,
list);
} else {
map.put(datatype,
new ArrayList<OperatorType>() {
private static final long serialVersionUID = 1L;
{
add(type);
}
});
}
});
}
return Collections.unmodifiableMap(new LinkedHashMap<>(map));
}
回答1:
Maybe something like this helps:
<D, K> Map<D, List<K>> swap(Map<K, List<D>> map) {
return map.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.map(v -> new SimpleEntry<>(v, e.getKey())))
.collect(Collectors.groupingBy(Entry::getKey,
Collectors.mapping(Entry::getValue,
Collectors.toList())));
}
Streams are not always the easiest solution to all kinds of problems. See @Flown's answer for a more understandable and easy non-stream solution.
You could write Flown's answer also "Stream-like" by using .forEach
, but it doesn't really get more readable (assuming values()
and getSupportedTypes()
both return a List
) and I wouldn't recommend it just to say that you are using streams:
OperatorType.values()
.forEach(type -> type.getSupportedTypes()
.forEach(dataType -> map.computeIfAbsent(dataType, dt -> new ArrayList<>())
.add(type)));
回答2:
A Stream
solution would require some flatmapping and tuple creation.
You should stick to nested loops.
private static Map<DataType, List<OperatorType>> buildmap() {
Map<DataType, List<OperatorType>> map = new HashMap<>();
for (OperatorType type : OperatorType.values()) {
for (DataType dataType : type.getSupportedTypes()) {
map.computeIfAbsent(dataType, dt -> new ArrayList<>()).add(type);
}
}
map.replaceAll((dt, ot) -> Collections.unmodifiableList(ot));
return Collections.unmodifiableMap(map);
}
回答3:
Since you seem to be using Guava, you can use their flattening multimap collector, invert it and return the map view:
private static Map<DataType, List<OperatorType>> buildmap() {
ImmutableListMultimap<OperatorType, DataType> flattened =
Arrays.stream(OperatorType.values())
.collect(ImmutableListMultimap.flatteningToImmutableListMultimap(
Function.identity(),
o -> o.getSupportedtypes().stream()));
return Multimaps.asMap(flattened.inverse());
}
回答4:
Here is a simple solution by StreamEx
EntryStream.of(map).flatMapValues(v -> v.stream()).invert().grouping();
来源:https://stackoverflow.com/questions/43718794/java-8-stream-how-to-convert-on-mapk-listd-to-mapd-listk