5
給定一系列項目,我想找到n個最頻繁的項目,按頻率降序排列。所以例如我想這個單元測試通過:習慣性的Clojure方法在seq中尋找最頻繁的項目
(fact "can find 2 most common items in a sequence"
(most-frequent-n 2 ["a" "bb" "a" "x" "bb" "ccc" "dddd" "dddd" "bb" "dddd" "bb"])
=>
'("bb" "dddd"))
我對Clojure相當新,仍然試圖抓住標準庫。這是我想出的:
(defn- sort-by-val [s] (sort-by val s))
(defn- first-elements [pairs] (map #(get % 0) pairs))
(defn most-frequent-n [n items]
"return the most common n items, e.g.
(most-frequent-n 2 [:a :b :a :d :x :b :c :d :d :b :d :b]) =>
=> (:d :b)"
(take n (->
items ; [:a :b :a :d :x :b :c :d :d :b :d :b]
frequencies ; {:a 2, :b 4, :d 4, :x 1, :c 1}
seq ; ([:a 2] [:b 4] [:d 4] [:x 1] [:c 1])
sort-by-val ; ([:x 1] [:c 1] [:a 2] [:b 4] [:d 4])
reverse ; ([:d 4] [:b 4] [:a 2] [:c 1] [:x 1])
first-elements))) ; (:d :b :a :c :x)
但是,這似乎是一個複雜的功能鏈,做一個相當普通的操作。有沒有更優雅或更習慣(或更有效率)的方式來做到這一點?
謝謝Mikera,你的解決方案是一個很好的改進。 (1)我看到如何正確使用箭頭宏以避免需要輔助函數。 (2)'sort-by'可以直接處理頻率結果,而不需要先執行seq。 (3)標準庫中有一個「第一」功能,所以我不需要創建自己的。 (4)在'map'之前執行'take'可能更有效。 –
'(反向(排序由F COL))'是非常昂貴的,沒有真正的原因 - 寧願改爲'(sort-by(comp -f)coll)'。此外,我會一致的關於你是否使用'first'和'second'或'key'和'val',因爲它們與map條目是等價的。 – amalloy