2015-06-05 19 views
4

我有一個常規列表如下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] 

有人可以幫助我?此外,我想在列表中找到最大出現在元素我的情況下其0xc10xc5

UPDATE:

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 } 

回答

5

有幾種方法可以做到這一點。開始學習Groovy的收藏方法的好地方是收集和注入。

方法collect爲舊的集合生成一個新的集合,並使用一個閉包來描述如何更改現有集合的每個元素以獲得新集合的新元素。

該方法注入生成一個給定集合的新對象。它需要一個閉包,它有兩個參數,一個用於運行的總體對象,另一個用於當前集合的成員,其中閉包體顯示如何修改集合的傳入成員的運行總數。一個常見的例子是總結一個數字列表(儘管這裏有一個方便的方法,總和)。

所以,你可以使用注入得到計數的地圖:

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] 

雖然這很醜陋。閉包代碼並不簡單,我必須從閉包中返回映射,以便更新運行總數。

從groupBy開始生成地圖,它只是不完全是你想要的地圖。有喜歡收集方法的方法,但專門的地圖,稱爲collectEntries,可以讓你從一個集合或映射變換元素,產生從一個新的地圖:

certs.groupBy().collectEntries { [(it.key) : it.value.size()] } 

但兩者都是不需要這個,因爲Groovy 1.8增加了一個更爲乾淨的countBy方法,更好的方法請參閱this other answer

一旦你的地圖生成,發現條目與最大的價值可以用

maxSize = m.values().max 
m.entrySet().findAll { it.value == maxSize } 
+0

可以請你幫我解決完成這個問題? https://stackoverflow.com/questions/47717505/groovy-create-a-map-with-jax-b-objects-specific-attributes – RanPaul

10
Map counts = certs.countBy { it } 
counts.findAll { it.value == counts.values().max() } 

或由一個班輪

certs.countBy { it }.groupBy { it.value }.max { it.key }.value.keySet() 
+1

我忘了countBy,+1 –

+0

@dmahapatro你能幫我嗎解決這個問題? https://stackoverflow.com/questions/47717505/groovy-create-a-map-with-jax-b-objects-specific-attributes – RanPaul