[英]Java8 : Efficient approach to manipulate Map
我有两个地图定义的地图,如下共享,基于 map1 中一个键的存在,我需要将条目复制到另一个地图。 下面的代码根据需要工作,但有没有更好和简单的方法来实现相同的目标。 您的建议表示赞赏。
Map<Object, HashSet<Map<Object, String>>> map1 = new HashMap<>();
Map<Object, HashSet<Map<Object, String>>> map2 = new HashMap<>();
map1.entrySet().stream().forEach(e -> {
Set<Map<Object, String>> infoMapSet = e.getValue();
infoMapSet.forEach(
inMap -> {
if (inMap.containsKey("isMerge")) {
Set<Map<Object, String>> set = new HashSet<>();
set.add(inMap);
map2.put(e.getKey(), set);
}
});
});
我写了一个功能更强大的方法,在我看来,它使代码更具可读性。 但是正如评论者已经指出的那样,您永远不会真正获得具有这种数据结构的简单、可读的解决方案。
首先,我将您的函数重写为实际函数,即取值并返回值。 因为你在上面所做的,本质上是取一个数据结构并过滤它。 在下面的代码中,我添加了您的原始函数并添加了一个更实用的函数。 请注意,我添加了 Vavr 作为依赖项,有关更多详细信息,请参阅Vavr (但仅将其用于 Tuple2 类,因此可以轻松地替换为您自己的实现)。
package com.example.demo;
import io.vavr.Tuple2;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class LegacyDataStructure {
public static Map<Object, Set<Map<Object,String>>> filteringFunction1(Map<Object, Set<Map<Object,String>>> origin) {
Map<Object,Set<Map<Object,String>>> map2 = new HashMap<>();
origin.entrySet().stream().forEach(e -> {
Set<Map<Object,String>> setInfo= e.getValue();
setInfo.forEach(inMap -> {
if(inMap.containsKey("isMerge")) {
HashSet<Map<Object,String>> set = new HashSet<>();
set.add(inMap);
map2.put(e.getKey(), set);
}
});
});
return map2;
}
public static Map<Object, Set<Map<Object, String>>> filteringFunction2(Map<Object, Set<Map<Object, String>>> origin) {
return origin
.entrySet()
.stream()
.map(e -> new Tuple2<>(
e.getKey(),
e.getValue()
.stream()
.filter(m -> m.containsKey("isMerge"))
.collect(Collectors.toSet())
)
)
.filter(t -> t._2().size() > 0)
.collect(Collectors.toMap(Tuple2::_1, Tuple2::_2));
}
}
您在filteringFunction2 中看到的情况是,我们获取entrySet 并将键与符合条件的值相关联,并过滤掉任何具有零匹配条件的键。
这是一个测试来证明这两个函数在它们产生的结果上是相同的:
package com.example.demo;
import io.vavr.Tuple2;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class FilteringTests {
@Test
public void bothFilteringMethodsShouldYieldSameResults() {
Map<Object, Set<Map<Object,String>>> testMap = new HashMap<>();
testMap.put(1, Set.of(Map.of("isMerge", "foo")));
testMap.put(2, Set.of(Map.of("notMerge", "bar")));
testMap.put(3, Set.of(Map.of("notMerge", "bar")));
var results1 = LegacyDataStructure.filteringFunction1(testMap);
var results2 = LegacyDataStructure.filteringFunction2(testMap);
assertEquals(1, results1.keySet().size());
assertEquals(1, results2.keySet().size());
results1.entrySet().forEach(e -> {
assertEquals(1, e.getKey());
var tuple = extractFirstEntry(e.getValue());
assertEquals("isMerge", tuple._1());
assertEquals("foo", tuple._2());
});
results2.entrySet().forEach(e -> {
assertEquals(1, e.getKey());
var tuple = extractFirstEntry(e.getValue());
assertEquals("isMerge", tuple._1());
assertEquals("foo", tuple._2());
});
}
private Tuple2<Object, String> extractFirstEntry(Set<Map<Object,String>> valueSet) {
return valueSet
.stream()
.findFirst()
.get()
.entrySet()
.stream()
.map(m -> new Tuple2<>(m.getKey(), m.getValue()))
.findFirst()
.get();
}
}
您可以通过使用Map.forEach
和Map.computeIfAbsent
来提高代码的可读性和表达性:
Map<Object, Set<Map<Object, String>>> map2 = new LinkedHashMap<>();
map1.forEach((key, setInfo) ->
setInfo.forEach(inMap -> {
if (inMap.containsKey("isMerge"))
map2.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(inMap);
}));
注意:我使用LinekdHashMap
和LinkedHashSet
来保留插入顺序。
同一个setInfo
HashSet 是否有可能具有多个满足此条件的映射?
如果是,则您的代码仅复制最后一张地图,因为前一张地图正在被替换。 所以代码应该固定如下。
map1.entrySet().stream().forEach(e -> {
HashSet<Map<Object,String>> setInfo= e.getValue();
HashSet<Map<Object, String>> set = new HashSet<>();
setInfo.forEach(inMap -> {
if (inMap.containsKey("isMerge")) {
set.add(inMap);
}
});
if (!set.isEmpty()) {
map2.put(e.getKey(), set);
}
});
否则,如果你保证同一个setInfo
HashSet 只能有一个满足这个条件的映射,那么一旦找到这样的映射,你就可以break
setInfo
的迭代。
map1.entrySet().stream().forEach(e -> {
HashSet<Map<Object,String>> setInfo= e.getValue();
for (Map<Object, String> inMap: setInfo) {
if (inMap.containsKey("isMerge")) {
HashSet<Map<Object, String>> set = new HashSet<>();
set.add(inMap);
map2.put(e.getKey(), set);
break;
}
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.