[英]How to make Map Optional on whether its every optional value is present
我有一個包含許多可選值的Map:
Map<MyCoolKey, Optional<MyCoolValue>>
我想將此Map轉換為Optional<Map<>>
:
Optional<Map<MyCoolKey, MyCoolValue>>
Optional<MyCoolValue>
都存在:應該存在Optional<Map<>>
。 Optional<MyCoolValue>
不存在: Optional<Map<>>
應該不存在。 我試過這個,我懷疑我的代碼會起作用,但它有點啰嗦:
final Map<MyCoolKey, Optional<MyCoolValue>> myCoolMap;
final Optional<Map<MyCoolKey, MyCoolValue>> optionalMap = myCoolMap
.entrySet()
.stream()
.map(e -> e
.getValue()
.flatMap(value -> Optional.<Map.Entry<MyCoolKey, MyCoolValue>>of(
new AbstractMap.SimpleEntry<>(
e.getKey(),
value
)
))
)
.collect(
() -> Optional.<Map<MyCoolKey, MyCoolValue>>of(new HashMap<>()),
(optAcc, optEntry) -> optAcc.flatMap(
acc -> optEntry.map(
entry -> {
acc.put(entry.getKey(), entry.getValue());
return acc;
})
),
(optAcc1, optAcc2) -> optAcc1.flatMap(
acc1 -> optAcc2.map(
acc2 -> {
acc1.putAll(acc2);
return acc1;
}
)
)
);
有一個更好的方法嗎? “更好”意味着正確,表現,美麗。 我更喜歡能夠在一個流中完成整個操作的答案。
下面是純流溶液的例子(不if
S和三元運營商)
final Map<MyCoolKey, Optional<MyCoolValue>> myCoolMap = new HashMap<>();
Optional<Map<MyCoolKey, MyCoolValue>> output = Optional.of(myCoolMap)
.filter(map -> map.values().stream().allMatch(Optional::isPresent))
.map(map -> map
.entrySet()
.stream()
.collect(toMap(
Map.Entry::getKey,
entry -> entry.getValue().get()
))
);
這不是過於復雜 - 過濾和映射是流的用途!
以下方法完成工作:
Map<MyCoolKey, Optional<MyCoolValue>> input;
Optional<Map<MyCoolKey, MyCoolValue>> output = convertMapWithOptionals(input);
我想出了這種方法的兩種“味道”:
1)不情願:首先檢查所有,然后開始轉換
<K, V> Optional<Map<K, V>> convertMapWithOptionals(Map<K, Optional<V>> map) {
if (!map.values().stream().allMatch(Optional::isPresent)) {
return Optional.empty();
}
return Optional.of(map.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey, entry -> entry.getValue().get()
)));
}
2)渴望:必要時開始轉換和中止
<K, V> Optional<Map<K, V>> convertMapWithOptionals(Map<K, Optional<V>> map) {
Map<K, V> result = new HashMap<>();
for (Map.Entry<K, Optional<V>> entry : map.entrySet()) {
if (!entry.getValue().isPresent()) {
return Optional.empty();
}
result.put(entry.getKey(), entry.getValue().get());
}
return Optional.of(result);
}
如果我理解正確的問題,你可以使用reduce
而不是collect
。 它允許您在收集期間更改accumulator
。
Optional<Map<MyCoolKey, MyCoolValue>> optionalMap = myCoolMap
.entrySet()
.stream()
.reduce(Optional.<Map<MyCoolKey, MyCoolValue>>of(new HashMap<>()),
(acc, entry) -> {
if (!acc.isPresent()) {
return acc;
}
if (!entry.getValue().isPresent()) {
return Optional.empty();
}
acc.get().put(entry.getKey(), entry.getValue().get());
return acc;
},
(acc, acc1) -> {
if (acc.isPresent() && acc1.isPresent()) {
acc.get().putAll(acc1.get());
return acc;
}
return Optional.empty();
}
);
我認為你通過嘗試將所有邏輯放在流中來過度復雜化。 只需過濾掉空的Optional
s,看看元素的數量是否相同:
Optional<Map<MyCoolKey, MyCoolValue>> result = Optional.of(
map.entrySet()
.stream()
.filter(e -> e.getValue().isPresent())
.collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get())
)
)
.filter(x-> x.size() == map.size());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.