Groovy:map减少映射列表



假设我在Groovy中有映射列表:

def listOfMaps = [
[k: 1, n: 'Name1', d1: 'a', d2: 'b'],
[k: 2, n: 'Name2', d1: 'c', d2: 'd'],
[k: 1, n: 'Name3', d1: 'e', d2: 'f'],
[k: 4, n: 'Name4', d1: 'g', d2: 'h']]

我需要找出是否存在(或不存在(项,其中k相等,但n不相等。例如,在这种情况下,我们有两个"k"=1的映射记录,"n"是"Name1"one_answers"Name3"。我怎样才能找到这样的数据?我想我应该按"k"分组,并计算"n"中的不同值,如果某个"k"的"n"有超过1个唯一值——我们发现了这样的数据。我完全陷入困境,所以任何帮助都将不胜感激。感谢

编辑

现在我已经明白了你的意思,下面是代码:

listOfMaps.groupBy { 
   it.k }.
values().
findAll { l -> 
   l.size() > 1 && (l.size() == l.unique { e -> e.n }.size()) 
}

一开始,列表按k元素分组,然后在值中搜索大小大于1且大小等于唯一n元素计数的列表。它工作正常。

旧答案

您可以尝试findAllunique:的组合

def listOfMaps = [
    [k: 1, n: 'Name1', d1: 'a', d2: 'b'],
    [k: 2, n: 'Name2', d1: 'c', d2: 'd'],
    [k: 1, n: 'Name3', d1: 'e', d2: 'f'],
    [k: 4, n: 'Name4', d1: 'g', d2: 'h'],
]
listOfMaps.findAll { it.k == 1 }.unique { it.n }

或使用groupBy:

listOfMaps.groupBy { it.k }[1].unique { it.n }

在groovy中有很多方法;(

listOfMaps.groupBy { [it.k, it.n] }.keySet().countBy { it[0] }.any { it.value > 1 }

您所需要的只是kn的组合来进行比较。你可以随心所欲地groupBy。我更喜欢按列表分组,这样我就可以getAt(0)来检查是否存在重复。由于keySet()Set,因此没有两个项目(列表(是相同的。然后我们只需要检查第一项(k(是否是唯一的。

如果您对精简版本感兴趣,此版本将构建k到一组ns的映射。

def r = listOfMaps.inject([:].withDefault{[].toSet()}) { m, it -> 
    m.get(it.k).add(it.n); m }
println r.findAll{ it.value.size()>1 }
// => [1:[Name3, Name1]]

我想不出一种方法来比较n,但尝试一下:

// Finds a match
assert [[k: 1, n: 'Name1', d1: 'a', d2: 'b'],
[k: 2, n: 'Name2', d1: 'c', d2: 'd'],
[k: 1, n: 'Name3', d1: 'e', d2: 'f'],
[k: 4, n: 'Name4', d1: 'g', d2: 'h']]
    .groupBy { it.k }    
    .collectEntries {k, v ->
        ["$k": v.unique()]
    }    
    .findAll { it.value.size() > 1 } != [:]
// Does not find a match
assert [[k: 2, n: 'Name2', d1: 'c', d2: 'd'],
[k: 1, n: 'Name3', d1: 'e', d2: 'f'],
[k: 4, n: 'Name4', d1: 'g', d2: 'h']]
    .groupBy { it.k }    
    .collectEntries {k, v ->
        ["$k": v.unique()]
    }    
    .findAll { it.value.size() > 1 } == [:]

编辑

我收回它。n可以与unique((进行比较:

[[k: 1, n: 'Name1', d1: 'a', d2: 'b'],
[k: 2, n: 'Name2', d1: 'c', d2: 'd'],
[k: 1, n: 'Name3', d1: 'e', d2: 'f'],
[k: 4, n: 'Name4', d1: 'g', d2: 'h']]
    .groupBy { it.k }    
    .collectEntries {k, v ->
        ["$k": v.unique { a, b -> (a.k == b.k && a.n == b.n) ? 0 : 1 }]
    }    
    .findAll { it.value.size() > 1 } != [:]

坐在马桶上能吐出来的东西真是太神奇了。

是的,Groovy确实非常棒,您可以使用不同的方法来实现相同的目标。

我将添加groupBy+unique+grep方法。这可能更容易理解。

基本上,您需要的是通过collect/unique来进行分组以减少维度,然后根据您获得的集合的大小进行grep。

def find = { 
    it.groupBy { it.k } // Fold one dimension
        .grep { it.value.size() > 1 } // filter results by that
        .grep { it.value*.n.unique().size() > 1 } // fold and repeat
        .collectEntries() // back to map
}
def listOfMaps = [
    [k: 1, n: 'Name1', d1: 'a', d2: 'b'],
    [k: 2, n: 'Name2', d1: 'c', d2: 'd'],
    [k: 1, n: 'Name3', d1: 'e', d2: 'f'],
    [k: 4, n: 'Name4', d1: 'g', d2: 'h']]

assert find(listOfMaps) == [1: [[k: 1, n: 'Name1', d1: 'a', d2: 'b'], [k: 1, n: 'Name3', d1: 'e', d2: 'f']]]
listOfMaps[2].n = "Name1" // Make them equals.
assert find(listOfMaps) == [:]    

迟到了,但这里还有一个:

listOfMaps.groupBy( [{ it.k }, { it.n }] )
        .findAll { _, v -> v.size() > 1}
        .collect { _, v -> v.values().collectMany{ it } }

与@Opal的回答相比,这允许列表包含重复项:

def listOfMaps = [
        [k: 2, n: 'Name2', d1: 'c', d2: 'd'],
        [k: 2, n: 'Name2', d1: 'c', d2: 'd'],
        [k: 2, n: 'Name3', d1: 'c', d2: 'd']
]

相关内容

  • 没有找到相关文章