有条件地从地图中删除密钥

时间:2015-10-08 07:57:53

标签: groovy

如果值是给定文本,我想有条件地删除集合,或者为null。

下面是一个简单的例子:

def map1 = [
        1: "#NULL",
        2: [
                2.1: "some value",
                2.2: "some value"
        ]]

assert map1.dropWhile { key, value ->
    value.equals("#NULL") || value == null
} == [2: [2.1: "some value", 2.2: "some value"]]

但是,这种下降虽然不处理子级别键和值。下面的一个将无法断言:

def map2 = [
        1: "#NULL",
        2: [
                2.1: "#NULL",
                2.2: "some value"
        ]]

assert map2.dropWhile { key, value ->
    value.equals("#NULL") || value == null
} == [2: [2.2: "some value"]]

有办法做到这一点吗?

<小时/> 蒂姆的回答后更新了 现在,下面的脚本将运行良好:

def defaultMap = [
        1: "some value",
        2: [
                2.1: "some value",
                2.2: "some value",
                2.3: [
                        "2.3.1": "some value",
                        "2.3.2": " some value"
                ]
        ]
]

def replacementMap = [2: [2.4: "some other value"]]

assert defaultMap.collectEntries(replacementMap) { mapKey, mapValue ->
    [mapKey, replacementMap.containsKey(mapKey) ? replacementMap[mapKey] : mapValue] // Remove default key and value pairs, if they are present in the replacement map.
                                                                                     // New key and value pairs in the replacement map will be preserved
}.collectEntries { mapKey, mapValue ->
    switch (mapValue) {
        case Map:
            return [mapKey, { -> mapValue.collectEntries owner }()]
        case '#NULL': // Remove key, if the value is also TEXT #NULL
            return [:]
        default:
            [mapKey, mapValue]
    }
} == [2: [2.4: 'some other value'], 1: 'some value']

但是,如果我想要使子图无效,但是将所有其他子图保持在同一级别,则它无法正常工作:

def defaultMap = [
        1: "some value",
        2: [
                2.1: "some value",
                2.2: "some value",
                2.3: [
                        "2.3.1": "some value",
                        "2.3.2": " some value"
                ]
        ]
]

def replacementMap = [2.3: '#NULL']

assert defaultMap.collectEntries(replacementMap) { mapKey, mapValue ->
    [mapKey, replacementMap.containsKey(mapKey) ? replacementMap[mapKey] : mapValue] // Remove default key and value pairs, if they are present in the replacement map.
                                                                                     // New key and value pairs in the replacement map will be preserved
}.collectEntries { mapKey, mapValue ->
    switch (mapValue) {
        case Map:
            return [mapKey, { -> mapValue.collectEntries owner }()]
        case '#NULL': // Remove key, if the value is also TEXT #NULL
            return [:]
        default:
            [mapKey, mapValue]
    }
} == [1:'some value', 2:[2.1:'some value', 2.2:'some value', 2.3:null]]

2 个答案:

答案 0 :(得分:2)

你可以写一个简单的递归地图漫步者:

def map2 = [
    '1': "#NULL",
    '2': [
        '2.1': "#NULL",
        '2.2': "some value"
    ]
]

def result = map2.collectEntries { name, value ->
    switch(value) {
        case Map:
            return [name, { -> value.collectEntries owner }()]
        case '#NULL':
            return [:]
        default:
            [name, value]
    }
}

assert result == ['2':['2.2':'some value']]

答案 1 :(得分:0)

您只需要使用递归方法:

def map2 = [
        1: "#NULL",
        2: [
                2.1: "#NULL",
                2.2: "some value"
        ]
]

def dropRecursive(Map m) {
    m.dropWhile { k, v ->
        if (v in Map) {
            m[k] = dropRecursive(v)
            return false
        } else {
            v == null || '#NULL'.equals(v)
        }
    }
}

assert dropRecursive(map2) == [2: [2.2: "some value"]]

在处理return false时需要使用Map,因为结果会投影到boolean表达式。由于groovy中非空Maptrue,因此也会将其删除,这是不需要的。尝试使用和不使用它进行实验。