たとえば ["john" "said"... "john" "walked"...] のような単語のベクトルがあり、各単語のハッシュ マップと次の単語の出現回数を作成したい場合{"ジョン" {"言った" 1 "歩いた" 1 "蹴った" 3}}
私が思いついた最善の解決策は、リストをインデックスごとに再帰的にウォークスルーし、assoc を使用してハッシュマップを更新し続けることでしたが、それは本当に厄介なようです。これを行うためのより慣用的な方法はありますか?
あなたが言葉を持っているとします:
(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}}
編集:次のような一時的なハッシュマップを使用してパフォーマンスを向上させることができます:
(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!))
結果として得られるソース コードは明らかに見栄えがよくないため、このような最適化は重要な場合にのみ行う必要があります。
transform*
(Criterium は、リア王の約 2 倍の速度でMichał Marczyks を上回っていると述べています)。