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()));
}