假设我有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”和“Name3”。我怎样才能找到这样的数据?
我想我应该按“k”分组并在“n”中计算不同的值,如果“n”中有超过1个唯一值用于某些“k” - 我们找到了这样的数据。
我完全陷入困境,所以任何帮助都会受到赞赏。
感谢
答案 0 :(得分:3)
修改强>
现在我已经找到了你的意思,这里是代码:
listOfMaps.groupBy {
it.k }.
values().
findAll { l ->
l.size() > 1 && (l.size() == l.unique { e -> e.n }.size())
}
在开始时,列表按k
元素分组,然后在我们搜索大小大于1且大小等于唯一n
元素数量的列表的值中。它工作正常。
OLD ANSWERS
您可以尝试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中有很多方法可以做到这一点;)
答案 1 :(得分:2)
listOfMaps.groupBy { [it.k, it.n] }.keySet().countBy { it[0] }.any { it.value > 1 }
您需要的只是k
&{39}和n
的组合进行比较。您可以按groupBy
的方式进行操作。我更喜欢按列表分组,以便我getAt(0)
检查是否存在重复项。由于keySet()
是Set
,因此没有两个项目(列表)将是相同的。然后我们只需检查第一项(k)是否唯一。
答案 2 :(得分:2)
如果您对缩小版感兴趣,可以将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]]
答案 3 :(得分:0)
我无法找到比较 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 } != [:]
坐在马桶上的东西真是太神奇了。
答案 4 :(得分:0)
是的,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) == [:]