1

重複する可能性がある場合に、2 つの [リスト、ベクトル、シーケンス] で共通の要素を見つけたいと考えています。

(common-elements [1] [1]) ; [1]
(common-elements [1 2] [1 1]) ; [1]
(common-elements [1 1] [1 1 1]) ; [1 1]

これが私が現在持っているものです:

(defn remove-first [elem coll]
  (lazy-seq
    (when-let [s (seq coll)]
      (let [f (first s), r (rest s)]
        (if (= elem f) 
          r 
          (cons f (remove-first elem r)))))))

(defn common-elements [coll1 coll2]
  (lazy-seq
    (when (and (seq coll1) (seq coll2))
      (let [f (first coll1)]
        (if (some #{f} coll2)
          (cons f (common-elements (rest coll1)
                                   (remove-first f coll2)))
          (common-elements (rest coll1) coll2)))))

4clojureを使った経験から、私は最も慣用的または簡潔なコードを書くことはめったにないことがわかったので、これを行うためのより良い方法があるかどうかを調べることに興味があります。

4

3 に答える 3

4

これが私の実装です。マップとセットを使用して中間データを保持するため、あなたのバージョンのように怠惰ではありませんが、より読みやすく、全体的なパフォーマンス特性が向上すると思います (あなたのバージョンは、共通要素からの結果を実現するために二次時間の複雑さを持っています)。

(require '[clojure.set :as set])
(defn common-elements [& colls]
  (let [freqs (map frequencies colls)]
    (mapcat (fn [e] (repeat (apply min (map #(% e) freqs)) e))
            (apply set/intersection (map (comp set keys) freqs)))))
于 2013-08-09T18:39:36.973 に答える
3

最も効率的ではありませんが、かなり簡潔です。

(defn common [& ss] 
  (let [fs (map frequencies ss), ks (map set ss)]
    (select-keys (apply merge-with min fs) 
                 (reduce clojure.set/intersection ks))))

値とカウントのマップを返します

(common [1] [1]) ;=> {1 1}
(common [1 2] [1 1]) ;=> {1 1}
(common [1 1] [1 1 1]) ;=> {1 2}

私自身の質問Idiomatic/Efficient Clojure way to intersect two apriori sortedvector? から変更された別のアプローチ?

(defn common [x y] 
  (loop [x (sort x) y (sort y) acc []] 
    (if (and x y)
      (let [x1 (first x) 
            y1 (first y)] 
      (cond 
        ( < x1 y1) (recur (next x) y acc) 
        ( > x1 y1) (recur x (next y) acc) 
        :else (recur (next x) (next y) (conj acc x1))))
    acc)))

元の質問のようにベクトルを返します

(common [1 1 1 2 2 3] [1 1 2 5]) ;=> [1 1 2]

もちろん、入力がソートされていることsortがわかっている場合は、を省略できます。また、それらがベクトルであることがさらにわかっている場合は、参照されている質問への回答で amalloy が提供する最適化を使用できます。

于 2013-08-09T18:39:06.717 に答える
1
(defn get-commons [l1 l2]
  (let [f1 (frequencies l1) 
        f2 (frequencies l2)
        common (clojure.set/intersection (set l1) (set l2))
        love (merge-with (fn [val1 val2] (min val1 val2)) f1 f2)] 
    (mapcat #(repeat (love %) %) common)))

この機能は、以前の回答で与えられたものと似ています。この質問に出くわす可能性のあるClojureの初心者のために、私はまだこの回答を提出しています。この関数によって、関数が結果を評価するために必要な手順がより明確になると思います。

于 2015-09-21T21:45:43.330 に答える