如果我有一个单词向量,例如 [“john”“said”...“john”“walked”...] 我想制作每个单词的 HashMap 以及下一个单词出现的次数,例如 {"john"{"said"1 "walked"1 "kicked"3}}
我想出的最好的解决方案是按索引递归地遍历列表并使用 assoc 来不断更新 HashMap ,但这看起来真的很困惑。有更惯用的方法吗?
最佳答案
既然你有话:
(def words ["john" "said" "lara" "chased" "john" "walked" "lara" "chased"])
使用这个转换-fn
(defn transform
[words]
(->> words
(partition 2 1)
(reduce (fn [acc [w next-w]]
;; could be shortened to #(update-in %1 %2 (fnil inc 0))
(update-in acc
[w next-w]
(fnil inc 0)))
{})))
(transform words)
;; {"walked" {"lara" 1}, "chased" {"john" 1}, "lara" {"chased" 2}, "said" {"lara" 1}, "john" {"walked" 1, "said" 1}}
编辑:您可以使用 transient HashMap 来提高性能,如下所示:
(defn transform-fast
[words]
(->> (map vector words (next words))
(reduce (fn [acc [w1 w2]]
(let [c-map (get acc w1 (transient {}))]
(assoc! acc w1 (assoc! c-map w2
(inc (get c-map w2 0))))))
(transient {}))
persistent!
(reduce-kv (fn [acc w1 c-map]
(assoc! acc w1 (persistent! c-map)))
(transient {}))
persistent!))
显然,生成的源代码看起来不太好,并且只有在至关重要时才应进行此类优化。
(Criterium 表示它击败了 Michał Marczyks transform*
,其速度大约是《李尔王》的两倍)。
关于Clojure简单马尔可夫数据变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20203883/