Groovy 列表:按元素计数分组并找到频率最高的元素
Groovy List : Group By element's count and find highest frequency elements
我有一个 groovy 列表如下
def certs = ['0xc1','0xc1','0xc1','0xc1','0xc2','0xc2','0xc3','0xc4','0xc4','0xc5','0xc5','0xc5','0xc5']
我正在尝试通过计数找到每个元素和组的出现。
我试过了
certs.groupBy { it }.findAll { it.value.size() }
但得到以下输出
[0xc1:[0xc1, 0xc1, 0xc1, 0xc1], 0xc2:[0xc2, 0xc2], 0xc3:[0xc3], 0xc4:[0xc4, 0xc4], 0xc5:[0xc5, 0xc5, 0xc5, 0xc5]]
相反,我期望低于
[0xc1:4, 0xc2:2, 0xc3:1, 0xc4:2, 0xc5:4]
有人可以帮我解决这个问题吗?另外我想在我的例子中找到列表中出现次数最多的元素 0xc1
和 0xc5
更新:
def myMap = certs.inject([:]) { m, x -> if (!m[x]) m[x] = 0; m[x] += 1; m }
def maxValue = myMap.values().max{it}
def myKeys = []
myMap.findAll{ it.value == maxValue }.each{myKeys << it?.key}
println myKeys // result = [0xc1:4, 0xc5:4]
//println myMap.sort { a, b -> b.value <=> a.value }
有几种方法可以做到这一点。开始学习 Groovy 的集合方法的一个好地方是收集和注入。
collect 方法为旧集合生成新集合,采用闭包描述如何更改现有集合的每个元素以获得新集合的新元素。
inject 方法在给定集合的情况下生成一个新对象。它需要一个带有两个参数的闭包,一个用于 运行 总对象,一个用于当前集合的成员,其中闭包的主体显示如何修改传递的 运行 总对象-在集合的成员中。一个常见的例子是对数字列表求和(尽管对于这种情况有一个方便的方法 sum)。
因此您可以使用注入获得计数图:
m = certs.inject([:]) { m, x -> if (!m[x]) m[x] = 0; m[x] += 1; m }
这对证书映射中的每个条目执行闭包,增加新映射中相同键的值,导致
[0xc1:4, 0xc2:2, 0xc3:1, 0xc4:2, 0xc5:4]
虽然这很丑陋。闭包代码并不简单,我必须从闭包中 return 地图,以便它会更新 运行 总数。
从groupBy开始生成地图,只是不是你想要的地图。有一种方法类似于 collect 方法,但专门用于映射,称为 collectEntries,它允许您转换一个集合或映射中的元素,并从中生成一个新映射:
certs.groupBy().collectEntries { [(it.key) : it.value.size()] }
但这两个都不是必需的,因为 Groovy 1.8 添加了一个 countBy 方法,可以更干净地完成此操作,请参阅 以获得更好的方法。
生成地图后,可以使用
找到具有最大值的条目
maxSize = m.values().max
m.entrySet().findAll { it.value == maxSize }
Map counts = certs.countBy { it }
counts.findAll { it.value == counts.values().max() }
或单程
certs.countBy { it }.groupBy { it.value }.max { it.key }.value.keySet()
我有一个 groovy 列表如下
def certs = ['0xc1','0xc1','0xc1','0xc1','0xc2','0xc2','0xc3','0xc4','0xc4','0xc5','0xc5','0xc5','0xc5']
我正在尝试通过计数找到每个元素和组的出现。 我试过了
certs.groupBy { it }.findAll { it.value.size() }
但得到以下输出
[0xc1:[0xc1, 0xc1, 0xc1, 0xc1], 0xc2:[0xc2, 0xc2], 0xc3:[0xc3], 0xc4:[0xc4, 0xc4], 0xc5:[0xc5, 0xc5, 0xc5, 0xc5]]
相反,我期望低于
[0xc1:4, 0xc2:2, 0xc3:1, 0xc4:2, 0xc5:4]
有人可以帮我解决这个问题吗?另外我想在我的例子中找到列表中出现次数最多的元素 0xc1
和 0xc5
更新:
def myMap = certs.inject([:]) { m, x -> if (!m[x]) m[x] = 0; m[x] += 1; m }
def maxValue = myMap.values().max{it}
def myKeys = []
myMap.findAll{ it.value == maxValue }.each{myKeys << it?.key}
println myKeys // result = [0xc1:4, 0xc5:4]
//println myMap.sort { a, b -> b.value <=> a.value }
有几种方法可以做到这一点。开始学习 Groovy 的集合方法的一个好地方是收集和注入。
collect 方法为旧集合生成新集合,采用闭包描述如何更改现有集合的每个元素以获得新集合的新元素。
inject 方法在给定集合的情况下生成一个新对象。它需要一个带有两个参数的闭包,一个用于 运行 总对象,一个用于当前集合的成员,其中闭包的主体显示如何修改传递的 运行 总对象-在集合的成员中。一个常见的例子是对数字列表求和(尽管对于这种情况有一个方便的方法 sum)。
因此您可以使用注入获得计数图:
m = certs.inject([:]) { m, x -> if (!m[x]) m[x] = 0; m[x] += 1; m }
这对证书映射中的每个条目执行闭包,增加新映射中相同键的值,导致
[0xc1:4, 0xc2:2, 0xc3:1, 0xc4:2, 0xc5:4]
虽然这很丑陋。闭包代码并不简单,我必须从闭包中 return 地图,以便它会更新 运行 总数。
从groupBy开始生成地图,只是不是你想要的地图。有一种方法类似于 collect 方法,但专门用于映射,称为 collectEntries,它允许您转换一个集合或映射中的元素,并从中生成一个新映射:
certs.groupBy().collectEntries { [(it.key) : it.value.size()] }
但这两个都不是必需的,因为 Groovy 1.8 添加了一个 countBy 方法,可以更干净地完成此操作,请参阅
生成地图后,可以使用
找到具有最大值的条目maxSize = m.values().max
m.entrySet().findAll { it.value == maxSize }
Map counts = certs.countBy { it }
counts.findAll { it.value == counts.values().max() }
或单程
certs.countBy { it }.groupBy { it.value }.max { it.key }.value.keySet()