地图上的Java8流媒体

地图上的Java8流媒体,java,java-8,java-stream,Java,Java 8,Java Stream,我有一张地图,我想在上面流淌 Map<LocalDate, Map<Integer, List<String>>> mainMap; 而childMap包含 {2016-02-23={120=[1,2,3], 121=[1,2,3], 122=[1,2,3], 123=[1,2,3]}} {2016-02-23=[120,123]} 我想从mainMap中删除这些值 预期产出=> {2016-02-23={121=[1,2,3], 122=[1,2,3]

我有一张地图,我想在上面流淌

Map<LocalDate, Map<Integer, List<String>>> mainMap;
而childMap包含

{2016-02-23={120=[1,2,3], 121=[1,2,3], 122=[1,2,3], 123=[1,2,3]}}
{2016-02-23=[120,123]}
我想从mainMap中删除这些值

预期产出=>

{2016-02-23={121=[1,2,3], 122=[1,2,3]}}

如何在Java 8中执行此操作?

您可以通过以下方法执行此操作:

mainMap.forEach((k, v) -> 
    v.keySet().removeIf(s -> 
        Optional.ofNullable(childMap.get(k)).map(o -> o.contains(s.toString())).orElse(false)
    )
);
这将遍历
mainMap
。然后,关于该映射的值,即
映射
,它删除所有整数键(转换为
字符串
),其中当前日期的
子映射
指向包含该键的列表。请注意,如果子映射不包含当前日期的列表,则不会删除整数键

完整的示例代码如下所示,用于打印所需的输出:

public static void main(String[] args) {
    Map<LocalDate, Map<Integer, List<String>>> mainMap = new HashMap<>();

    Map<Integer, List<String>> map = new HashMap<>();
    map.put(120, Arrays.asList("1", "2", "3"));
    map.put(121, Arrays.asList("1", "2", "3"));
    map.put(122, Arrays.asList("1", "2", "3"));
    map.put(123, Arrays.asList("1", "2", "3"));
    mainMap.put(LocalDate.of(2016, 2, 23), map);

    Map<LocalDate, List<String>> childMap = new HashMap<>();
    childMap.put(LocalDate.of(2016, 2, 23), Arrays.asList("120", "123"));

    mainMap.forEach((k, v) -> 
        v.keySet().removeIf(s -> 
            Optional.ofNullable(childMap.get(k)).map(o -> o.contains(s.toString())).orElse(false)
        )
    );

    System.out.println(mainMap);
}
publicstaticvoidmain(字符串[]args){
Map mainMap=新的HashMap();
Map Map=newhashmap();
map.put(120,数组.asList(“1”、“2”、“3”);
map.put(121,数组.asList(“1”、“2”、“3”);
map.put(122,数组.asList(“1”、“2”、“3”);
map.put(123,数组.asList(“1”、“2”、“3”);
mainMap.put(LocalDate.of(2016,2,23),map);
Map childMap=newhashmap();
childMap.put(LocalDate.of(2016,2,23),Arrays.asList(“120”,“123”);
主地图forEach((k,v)->
v、 键集().removeIf(s->
可选.ofNullable(childMap.get(k)).map(o->o.contains(s.toString()).orElse(false)
)
);
System.out.println(主地图);
}
is的替代方案

不同之处在于,Tunaki的解决方案将迭代
mainMap
中包含的子映射的内容,并对每个子映射执行
childMap
查找,而上述解决方案将迭代
childMap
中找到的列表,并对
mainMap
的子映射执行查找。当子贴图和列表的大小都增大时,这是最好的

有一件事还没有解决,那就是如果
mainMap
的子映射由于操作而被清空,是否应该删除它们的映射。在对要修改的映射进行迭代时,不可能一次删除外部映射(除非使用
迭代器求助于旧循环)

解决方案是迭代
childMap
,然后:

childMap.forEach((k,v) -> mainMap.computeIfPresent(k, (d,m) -> {
    v.stream().map(Integer::valueOf).forEach(m::remove);
    return m.isEmpty()? null: m;
}));
请注意,最复杂的情况是两个映射之间的类型不匹配,因此必须执行
childMap
String
s到
mainMap
Integer
s之间的转换。如果它们具有相同的类型,例如,如果
childMap
Map
mainMap
Map
,则不删除空映射的解决方案非常简单

mainMap.forEach((k, v) -> v.keySet().removeAll(childMap.getOrDefault(k, emptyList())));
以及从外部映射中删除空映射的解决方案:

childMap.forEach((k,v) -> mainMap.computeIfPresent(k, (d,m) -> {
    m.keySet().removeAll(v);
    return m.isEmpty()? null: m;
}));
上面的代码可能会删除到初始空映射的映射。如果仅当映射在此操作期间已清空时(即不接触开始时为空的映射),才要删除映射,则代码会变得更简单:

childMap.forEach((k,v) ->
    mainMap.computeIfPresent(k, (d,m) -> m.keySet().removeAll(v) && m.isEmpty()? null: m));

如果
childMap
{2016-02-23=[120121122123]}
,那么输出会是什么?我的观点是。。。外部地图的输入会发生什么?它必须是空映射还是也必须删除映射到空内部映射的条目?如果childMap为{2016-02-23=[120121122123]},输出将是什么?我的观点是。。。外部地图的输入会发生什么?它必须是一个空映射,还是您也必须删除映射到空内部映射的条目?(我问了OP同样的问题)@Federicoperaltachaffner这是个好问题。OP并没有具体说明那个案例。我的回答会产生一张空的内心地图。您可以通过调用
mainMap.values().removeIf(Map::isEmpty)来考虑这一点
forEach
之后。
childMap.forEach((k,v) -> mainMap.computeIfPresent(k, (d,m) -> {
    m.keySet().removeAll(v);
    return m.isEmpty()? null: m;
}));
childMap.forEach((k,v) ->
    mainMap.computeIfPresent(k, (d,m) -> m.keySet().removeAll(v) && m.isEmpty()? null: m));