3

たとえば ["john" "said"... "john" "walked"...] のような単語のベクトルがあり、各単語のハッシュ マップと次の単語の出現回数を作成したい場合{"ジョン" {"言った" 1 "歩いた" 1 "蹴った" 3}}

私が思いついた最善の解決策は、リストをインデックスごとに再帰的にウォークスルーし、assoc を使用してハッシュマップを更新し続けることでしたが、それは本当に厄介なようです。これを行うためのより慣用的な方法はありますか?

4

2 に答える 2

6

あなたが言葉を持っているとします:

(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 を上回っていると述べています)。

于 2013-11-25T21:45:45.010 に答える