Groovy:按多个值从地图列表中删除重复项

Groovy: Remove duplicates from a list of maps by multiple values

有这样的地图列表

def listOfMaps = 
[
    ["car": "A", "color": "A", "motor": "A", "anything": "meh"],
    ["car": "A", "color": "A", "motor": "A", "anything": "doesn't matter"],
    ["car": "A", "color": "A", "motor": "B", "anything": "Anything"],
    ["car": "A", "color": "B", "motor": "A", "anything": "Anything"]
]

我应该如何按汽车、颜色和马达查找重复项?如果有超过 1 张地图具有相同的汽车、颜色和电机值,则它应该 return 为真。在这种情况下,它应该 return 为真,因为第一张和第二张地图具有相同的汽车、颜色和电机值,只要它们相同,值可以是任何值。

Groovy 有一个方便的 Collection.unique(boolean,closure) 方法,允许您根据闭包中定义的比较器从输入列表中删除重复项来创建新列表。在您的情况下,您可以定义一个闭包,首先比较 car 字段,然后比较 color,最后 - motor。任何与所有这些字段重复值的元素都将被过滤掉。

考虑以下示例:

def listOfMaps = [
    ["car": "A", "color": "A", "motor": "A", "anything": "meh"],
    ["car": "A", "color": "A", "motor": "A", "anything": "doesn't matter"],
    ["car": "A", "color": "A", "motor": "B", "anything": "Anything"],
    ["car": "A", "color": "B", "motor": "A", "anything": "Anything"]
]

// false parameter below means that the input list is not modified
def filtered = listOfMaps.unique(false) { a, b ->
    a.car <=> b.car ?:
        a.color <=> b.color ?:
        a.motor <=> b.motor
}

println filtered

boolean hasDuplicates = listOfMaps.size() > filtered.size()

assert hasDuplicates

输出:

[[car:A, color:A, motor:A, anything:meh], [car:A, color:A, motor:B, anything:Anything], [car:A, color:B, motor:A, anything:Anything]]

不确定我是否正确理解了问题,但我想出了下一个代码片段:

def listOfMaps = [
    ["car": "A", "color": "A", "motor": "A", "anything": "meh"],
    ["car": "A", "color": "A", "motor": "A", "anything": "doesn't matter"],
    ["car": "A", "color": "A", "motor": "B", "anything": "Anything"],
    ["car": "A", "color": "B", "motor": "A", "anything": "Anything"]
]

static def findDuplicatesByKeys(List<Map<String, String>> maps, List<String> keys) {
    Map<String, List<Map<String, String>>> aggregationKeyToMaps = [:].withDefault { key -> []}

    maps.each { singleMap ->
        def aggregationKey = keys.collect { key -> singleMap[key] }.join('-')

        aggregationKeyToMaps.get(aggregationKey).add(singleMap)
    }

    aggregationKeyToMaps
}

findDuplicatesByKeys(listOfMaps, ['car', 'color', 'motor'])

基本上它遍历映射列表并按提供的键的值对它们进行分组。结果将是地图列表地图。类似于:

def aggregatedMaps = [
    "A-A-A": [
        ["car": "A", "color": "A", "motor": "A", "anything": "meh"],
        ["car": "A", "color": "A", "motor": "A", "anything": "doesn't matter"]
    ],
    "A-A-B": [
        ["car": "A", "color": "A", "motor": "B", "anything": "Anything"]
    ],
    "A-B-A": [
        ["car": "A", "color": "B", "motor": "A", "anything": "Anything"]
    ]
]

例如,您可以获取 .values() 并应用所需的删除(您尚未指定应删除哪个重复项)并最终展平列表。希望对您有所帮助。

您可以按适当的字段对地图进行分组,然后检查是否存在至少一个包含不止一个元素的组:

boolean result = listOfMaps
         .groupBy { [car: it.car, color: it.color, motor: it.motor] }
         .any { it.value.size() > 1 }