将Java 8中的映射值与流相结合

  • 本文关键字:相结合 映射 Java java
  • 更新时间 :
  • 英文 :


我有两个Map,它们应该具有相同的密钥(假设)。

我需要对相应的元素执行操作

Java 7代码:

Map<X,Y> m1, m2;
for (Map.Entry<X,Y> kvp: m1.entrySet()) {
    K key = kvp.getKey();
    Y value1 = kvp.getValue();
    Y value2 = m2.get(key);    

    doSomething(value1, value2);
}

我的目标是使用lambda进行这种操作

类似的东西

Map<X,Y> m1, m2;
[initStreamHere](m1, m2).forEachCorrespondingEntry((k, v1, v2)-> doSomething(v1, v2));

通常,根据对应密钥的存在与否,v1v2是否为空可能是很酷的。

Java提供了这样酷的功能吗?或者可以用不到50行的自定义代码实现吗?

我的目标是使用一个lambda表达式,该表达式接受键和两个相应的值

只要这只是一个奇怪的问题。对于生产/你的同事来说,最好写一些更容易理解的东西。

interface EntryConsumer<K, V> {
    void apply(K key, V v1, V v2);
}
public static <K, V> void fancyStreams(Map<K, V> m1, Map<K, V> m2, EntryConsumer<K, V> consumer) {
    Stream
        .concat(m1.entrySet().stream(), m2.entrySet().stream())
        .filter(e -> e.getValue() != null) // filter out nulls
        .collect(Collectors.groupingBy(Map.Entry::getKey))
        .entrySet()
        .stream()
        .filter(e -> e.getValue().size() == 2) // filter out non-matching key-values
        .forEach(e -> consumer.apply(e.getKey(), e.getValue().get(0).getValue(), e.getValue().get(1).getValue()));
}
public static <K, V> void plainOldIteration(Map<K, V> m1, Map<K, V> m2, EntryConsumer<K, V> consumer) {
    m1.entrySet()
        .forEach(e -> {
            if (m2.containsKey(e.getKey())) 
                consumer.apply(e.getKey(), e.getValue(), m2.get(e.getKey()))
        });
}
// Actual usage
Map<String, Integer> m1, m2;
m1 = Maps.of("1", 22, "2", 23);
m2 = Maps.of("1", 20, "2", 19, "3", 21);
fancyStreams(m1, m2, (k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));
plainOldIteration(m1, m2, (k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));

以及您的实际请求(稍微详细一点)

public class EntryStream<K, V> {
    private final Map<K, V> m1;
    private final Map<K, V> m2;
    private EntryStream(Map<K, V> m1, Map<K, V> m2) {
        this.m1 = m1;
        this.m2 = m2;
    }
    public static <K, V> EntryStream<K, V> of(Map<K, V> m1, Map<K, V> m2) {
        return new EntryStream<>(m1, m2);
    }
    public void forEachCorrespondingEntry(EntryConsumer<K, V> consumer) {
        m1.entrySet()
            .forEach(e -> {
                if (m2.containsKey(e.getKey())) consumer.apply(e.getKey(), e.getValue(), m2.get(e.getKey()));
            });
    }
}
// Usage
EntryStream.of(m1, m2).forEachCorrespondingEntry((k, v1, v2) -> System.out.println(k + ": " + (v1 + v2)));

这里我写了一个很好的例子,说明如何使用merge函数来实现您的目的。

public class MapCombine {
    
    public static Map<String,Integer> combineMaps(Map<String,Integer>map1,Map<String,Integer>map2){
        map2.forEach((key,value)->{
            map1.merge( key, map1.get(key), MapCombine::combine);   
        });
        return map1;
    }
    public static int combine(Integer a , Integer b) {
        return a+b;
    }
    
    public static void main (String ...args) {
        Map<String,Integer>map1 = new HashMap<>();
        Map<String,Integer>map2 = new HashMap<>();
        map1.put("Red", 1);
        map1.put("Blue", 12);
        map1.put("Black", 11);
        map2.put("Red", 1);
        map2.put("Blue", 111);      
        
        // This will print total for each color
        System.out.println(combineMaps(map1, map2));
    }
}

这是输出:{红=2,蓝=24,黑=11}

类似的东西?

m1.entrySet()
  .stream()
  .filter(kvp -> m2.containsKey(kvp.getKey()))
  .forEach(kvp -> doSomething(kvp.getValue(), m2.get(kvp.getKey())));

最新更新