Groovy:map reduceMap列表

rdrgkggo  于 2023-03-11  发布在  其他
关注(0)|答案(6)|浏览(324)

假设我在Groovy中有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']]

我需要找到是否存在(或不)项,其中k相等,但n不相等。例如,在这种情况下,我们有两个Map记录,“k”= 1,“n”为“Name 1”和“Name 3”。我如何找到这样的数据?我想我应该按“k”分组,并计算“n”中的不同值,如果有超过1唯一值在“n”为某些“k”-我们发现这样的数据。我完全卡住了,所以任何帮助将不胜感激。谢谢

pvcm50d1

pvcm50d11#

编辑

现在我明白你的意思了,代码如下:

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中,有很多方法可以实现这一点;)

nzk0hqpo

nzk0hqpo2#

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

您所需要的只是一个kn的组合来进行比较。您可以按照自己的方式来使用groupBy。我更喜欢按列表分组,以便可以使用getAt(0)来检查是否存在重复项。由于keySet()Set,没有两个条目(列表)是相同的。2然后我们只需要检查第一个条目(k)是否是唯一的。

fquxozlt

fquxozlt3#

如果您对简化版本感兴趣,这个版本将构建k到一组n的Map。

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]]
t5zmwmid

t5zmwmid4#

我想不出比较 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 } != [:]

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

tkclm6bt

tkclm6bt5#

是的,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) == [:]
4ktjp1zp

4ktjp1zp6#

很晚了,不过还有一个

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']
]

相关问题