Java 使用流API在两个HashMap之间执行操作
我在表单中有两个哈希映射Java 使用流API在两个HashMap之间执行操作,java,hashmap,java-8,java-stream,Java,Hashmap,Java 8,Java Stream,我在表单中有两个哈希映射 Map<Integer, Map<String,Double>> MAP_1 Map<Integer, Map<String,Double>> MAP_2 因此,关于外部地图,只需考虑ID1;反过来,操作必须涉及内部(通用)键“2016-10-02”和“2016-10-03” 这是我当前的代码 Set<Integer> common_keys = new LinkedHashSet<Integer&g
Map<Integer, Map<String,Double>> MAP_1
Map<Integer, Map<String,Double>> MAP_2
因此,关于外部地图,只需考虑ID1;反过来,操作必须涉及内部(通用)键“2016-10-02”和“2016-10-03”
这是我当前的代码
Set<Integer> common_keys = new LinkedHashSet<Integer>(map1.keySet());
common_keys.retainAll(map2.keySet());
System.out.println("Common keys: "+common_keys.toString());
map1.forEach((k,v) -> {
Map<String,Double> submap_1 = new LinkedHashMap<String,Double>(v);
Map<String,Double> submap_2 = new LinkedHashMap<String,Double>(map2.get(k));
Set<String> commons = new LinkedHashSet<String>(submap_1.keySet());
commons.retainAll(submap_2.keySet());
System.out.println(k+" : common days: "+commons);
List<Double> val1 = submap_1.keySet()
.stream()
.filter(c -> commons.contains(c))
.map(c -> submap_1.get(c))
.collect(Collectors.toList());
List<Double> val2 = submap_2.keySet()
.stream()
.filter(c -> commons.contains(c))
.map(c -> submap_2.get(c))
.collect(Collectors.toList());
List<Double> ABS = IntStream.range(0, val1.size())
.mapToObj(i -> val1.get(i) - val2.get(i))
.collect(Collectors.toList());
diff_abs.put(k, ABS);
});
Set common_keys=newlinkedhashset(map1.keySet());
公共_keys.retainal(map2.keySet());
System.out.println(“公共键:+Common_-keys.toString());
图1.forEach((k,v)->{
Map submap_1=新的LinkedHashMap(v);
Map submap_2=newlinkedhashmap(map2.get(k));
Set commons=newlinkedhashset(submap_1.keySet());
commons.retainal(submap_2.keySet());
System.out.println(k+”:公共日:“+公共日);
List val1=submap_1.keySet()
.stream()
.filter(c->commons.contains(c))
.map(c->submap_1.get(c))
.collect(Collectors.toList());
List val2=submap_2.keySet()
.stream()
.filter(c->commons.contains(c))
.map(c->submap_2.get(c))
.collect(Collectors.toList());
List ABS=IntStream.range(0,val1.size())
.mapToObj(i->val1.get(i)-val2.get(i))
.collect(Collectors.toList());
不同的abs.put(k,abs);
});
有没有一种更简单、更智能的方法,通过使用Java8的流API来做到这一点
提前感谢以上示例中的几点。我的
列表
、集合
和映射
的实现是数组列表
、哈希集合
和哈希映射
,除非我需要它们的链接
实现特别提供的东西,即一致的顺序(但这种情况极少发生)
以下是我的做法:
public static <T, S> Map<T, List<Double>> method(
Map<T, Map<S, Double>> map1,
Map<T, Map<S, Double>> map2)
{
Set<T> commonKeys = intersection(map1.keySet(), map2.keySet());
return commonKeys.stream().collect(Collectors.toMap(
Function.identity(),
key -> {
Map<S, Double> inner1 = map1.get(key);
Map<S, Double> inner2 = map2.get(key);
Set<S> innerCommonKeys = intersection(
inner1.keySet(),
inner2.keySet());
return innerCommonKeys.stream().map(innerKey ->
inner1.get(innerKey) - inner2.get(innerKey))
.collect(Collectors.toList());
}));
}
private static <T> Set<T> intersection(Set<T> set1, Set<T> set2) {
Set<T> intersection = new HashSet<T>(set1);
intersection.retainAll(set2);
return intersection;
}
公共静态映射方法(
地图1,
地图(地图2)
{
设置commonKeys=intersection(map1.keySet(),map2.keySet());
返回commonKeys.stream().collect(Collectors.toMap(
Function.identity(),
键->{
Map inner1=map1.get(键);
Map inner2=map2.get(键);
设置innerCommonKeys=交点(
inner1.keySet(),
inner2.keySet());
返回innerCommonKeys.stream().map(innerKey->
inner1.get(innerKey)-inner2.get(innerKey))
.collect(Collectors.toList());
}));
}
专用静态集合交叉点(集合集合1、集合2){
集合交集=新哈希集合(集合1);
交叉口。保留(set2);
折返交叉口;
}
这里有一个“测试”来证明它是有效的:
public static void main(String[] args)
{
Map<String, Map<String, Double>> map1 = new HashMap<>();
Map<String, Double> inner11 = new HashMap<>();
inner11.put("2016-10-02", 10.0);
inner11.put("2016-10-03", 20.0);
inner11.put("2016-10-04", 30.0);
map1.put("ID1", inner11);
Map<String, Double> inner12 = new HashMap<>();
inner12.put("2016-10-02", 1.00);
inner12.put("2016-10-03", 2.00);
inner12.put("2016-10-04", 3.00);
map1.put("ID2", inner12);
Map<String, Map<String, Double>> map2 = new HashMap<>();
Map<String, Double> inner21 = new HashMap<>();
inner21.put("2016-10-02", 2.00);
inner21.put("2016-10-03", 3.00);
map2.put("ID1", inner21);
Map<String, Double> inner22 = new HashMap<>();
inner22.put("2016-10-02", 1.00);
inner22.put("2016-10-03", 2.00);
inner22.put("2016-10-04", 3.00);
map2.put("ID3", inner22);
System.out.println(method(map1, map2));
}
publicstaticvoidmain(字符串[]args)
{
Map map1=新的HashMap();
Map inner11=新的HashMap();
11.put(“2016-10-02”,10.0);
11.put(“2016-10-03”,20.0);
11.put(“2016-10-04”,30.0);
map1.put(“ID1”,inner11);
Map inner12=新的HashMap();
12.put(“2016-10-02”,1.00);
12.put(“2016-10-03”,2.00);
12.put(“2016-10-04”,3.00);
map1.put(“ID2”,inner12);
Map map2=新的HashMap();
Map inner21=新的HashMap();
inner21.put(“2016-10-02”,2.00);
inner21.put(“2016-10-03”,3.00);
map2.put(“ID1”,inner21);
Map inner22=新的HashMap();
22.put(“2016-10-02”,1.00);
22.put(“2016-10-03”,2.00);
22.put(“2016-10-04”,3.00);
map2.put(“ID3”,inner22);
System.out.println(方法(map1,map2));
}
输出:
{ID1=[8.0,17.0]}
不需要创建集。对于另一个映射中的同一个键,将其替换为检查中的null
in。此外,创建映射副本是不必要的,因为该方法中从不修改映射
public static <T, U> Map<T, List<Double>> merge(Map<T, Map<U, Double>> m1, Map<T, Map<U, Double>> m2) {
Map<T, List<Double>> result = new HashMap<>();
m1.forEach((k, v) -> {
Map<U, Double> v2 = m2.get(k);
if (v2 != null) {
// both outer maps contain the same key
ArrayList<Double> list = new ArrayList<>();
v.forEach((innerK, innerV) -> {
Double d = v2.get(innerK);
if (d != null) {
// matching key in both inner maps
list.add(innerV - d);
}
});
// list.trimToSize();
result.put(k, list);
}
});
return result;
}
公共静态地图合并(地图m1、地图m2){
映射结果=新的HashMap();
m1.forEach((k,v)->{
Map v2=m2.get(k);
如果(v2!=null){
//两个外部映射包含相同的键
ArrayList=新建ArrayList();
v、 forEach((innerK,innerV)->{
双d=v2.get(innerK);
如果(d!=null){
//在两个内部映射中匹配密钥
添加(innerV-d);
}
});
//list.trimToSize();
结果.put(k,list);
}
});
返回结果;
}
您可以创建一种可重复使用的方法,通过仅保留公用键并对两个值应用函数来合并两个贴图:
public static <K,V,R> Map<K, R> merge(Map<K,V> map1, Map<K,V> map2, BiFunction<V,V,R> f) {
boolean hasOrder=map1.entrySet().spliterator().hasCharacteristics(Spliterator.ORDERED);
return map1.entrySet().stream()
.collect(hasOrder? LinkedHashMap<K,R>::new: HashMap<K,R>::new, (m,e)-> {
V v2 = map2.get(e.getKey());
if(v2!=null) m.put(e.getKey(), f.apply(e.getValue(), v2));
}, Map::putAll);
}
公共静态地图合并(地图地图1、地图地图2、双功能f){
boolean hasOrder=map1.entrySet().spliterator().hasCharacteristics(spliterator.ORDERED);
返回map1.entrySet().stream()
.collect(hasOrder?LinkedHashMap::new:HashMap::new,(m,e)->{
V v2=map2.get(e.getKey());
如果(v2!=null)m.put(e.getKey(),f.apply(e.getValue(),v2));
},地图::putAll);
}
然后,可以通过两次使用该方法轻松实现嵌套贴图的合并:
public static <K1, K2> Map<K1, List<Double>> merge(
Map<K1, Map<K2, Double>> map1, Map<K1, Map<K2, Double>> map2) {
return merge(map1, map2,
(a,b) -> new ArrayList<>(merge(a, b, (x,y) -> x-y).values()));
}
公共静态映射合并(
地图1,地图2){
返回合并(map1、map2、,
(a,b)->newarraylist(merge(a,b,(x,y)->x-y.values());
}
请注意,上面的代码足够聪明,可以创建LinkedHashMap
如果且仅当第一个映射具有内在顺序,例如,它本身是LinkedHashMap
或SortedMap
,否则是普通的HashMap
。第二个映射的顺序无论如何都不会保留,如果正如您的原始代码所假设的那样,两个映射具有相同的顺序,则这不是问题。如果它们的顺序不同,显然无法同时保留这两个顺序。为什么要使用流API?如果常规代码对你有用,就使用常规代码。我已经在我的代码中使用了流API。我想知道它是否存在一个更大的c
public static <T, U> Map<T, List<Double>> merge(Map<T, Map<U, Double>> m1, Map<T, Map<U, Double>> m2) {
Map<T, List<Double>> result = new HashMap<>();
m1.forEach((k, v) -> {
Map<U, Double> v2 = m2.get(k);
if (v2 != null) {
// both outer maps contain the same key
ArrayList<Double> list = new ArrayList<>();
v.forEach((innerK, innerV) -> {
Double d = v2.get(innerK);
if (d != null) {
// matching key in both inner maps
list.add(innerV - d);
}
});
// list.trimToSize();
result.put(k, list);
}
});
return result;
}
public static <K,V,R> Map<K, R> merge(Map<K,V> map1, Map<K,V> map2, BiFunction<V,V,R> f) {
boolean hasOrder=map1.entrySet().spliterator().hasCharacteristics(Spliterator.ORDERED);
return map1.entrySet().stream()
.collect(hasOrder? LinkedHashMap<K,R>::new: HashMap<K,R>::new, (m,e)-> {
V v2 = map2.get(e.getKey());
if(v2!=null) m.put(e.getKey(), f.apply(e.getValue(), v2));
}, Map::putAll);
}
public static <K1, K2> Map<K1, List<Double>> merge(
Map<K1, Map<K2, Double>> map1, Map<K1, Map<K2, Double>> map2) {
return merge(map1, map2,
(a,b) -> new ArrayList<>(merge(a, b, (x,y) -> x-y).values()));
}