假设我在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
元素计数的列表。它工作正常。
旧答案
您可以尝试findAll
和unique
:的组合
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 }
您所需要的只是k
和n
的组合来进行比较。你可以随心所欲地groupBy
。我更喜欢按列表分组,这样我就可以getAt(0)
来检查是否存在重复。由于keySet()
是Set
,因此没有两个项目(列表(是相同的。然后我们只需要检查第一项(k(是否是唯一的。
如果您对精简版本感兴趣,此版本将构建k
到一组n
s的映射。
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']
]