在clojure中检查奇数奇偶校验

时间:2014-10-25 17:47:11

标签: clojure functional-programming

我有以下函数来检查序列中的奇校验

(defn countOf[a-seq elem]
   (loop [number 0 currentSeq a-seq]
      (cond (empty? currentSeq) number
          (= (first currentSeq) elem) (recur (inc number) (rest currentSeq))
            :else (recur number (rest currentSeq))
      )
   )
 )

(defn filteredSeq[a-seq elemToRemove]
  (remove (set (vector (first a-seq))) a-seq)
  )

(defn parity [a-seq]
  (loop [resultset [] currentSeq a-seq]
    (cond (empty? currentSeq) (set resultset)
           (odd? (countOf currentSeq (first currentSeq))) (recur (concat resultset (vector(first currentSeq))) (filteredSeq currentSeq (first currentSeq)))
           :else (recur resultset (filteredSeq currentSeq (first currentSeq)))
    )
  )
)

例如(奇偶校验[1 1 1 2 2 3]) - > (1 3)就是从序列中挑选奇数个元素。

  1. 有没有更好的方法来实现这一目标?

  2. 如何通过clojure的 reduce 功能来完成

2 个答案:

答案 0 :(得分:2)

首先,我决定为你的代码制作更多惯用版本,所以我真的能看到它在做什么:

;; idiomatic naming
;; no need to rewrite count and filter for this code
;; putting item and collection in idiomatic argument order
(defn count-of [elem a-seq]
  (count (filter #(= elem %) a-seq)))

;; idiomatic naming
;; putting item and collection in idiomatic argument order
;; actually used the elem-to-remove argument
(defn filtered-seq [elem-to-remove a-seq]
  (remove #(= elem-to-remove %) a-seq))

;; idiomatic naming
;; if you want a set, use a set from the beginning
;; destructuring rather than repeated usage of first
;; use rest to recur when the first item is guaranteed to be dropped
(defn idiomatic-parity [a-seq]
  (loop [result-set #{}
         [elem & others :as current-seq] a-seq]
    (cond (empty? current-seq)
          result-set
          (odd? (count-of elem current-seq))
          (recur (conj result-set elem) (filtered-seq elem others))
          :else
          (recur result-set (filtered-seq elem others)))))

接下来,根据要求,使用reduce累积结果的版本:

;; mapcat allows us to return 0 or more results for each input
(defn reducing-parity [a-seq]
  (set
   (mapcat
    (fn [[k v]]
      (when (odd? v) [k]))
    (reduce (fn [result item]
              (update-in result [item] (fnil inc 0)))
            {}
            a-seq))))

但是,阅读本文后,我注意到reduce只是frequencies,内置了clojure函数。我的mapcat实际上只是一个手动keep,另一个是内置的。

(defn most-idiomatic-parity [a-seq]
  (set
   (keep
    (fn [[k v]]
      (when (odd? v) k))
    (frequencies a-seq))))

在Clojure中,我们可以优化我们的代码,并且当我们识别出逻辑复制内置功能的地方时,我们可以简化代码并使其更加清晰。此外,内置的机会很可能比我们自己的工作更好。

答案 1 :(得分:0)

有没有更好的方法来实现这一目标?

(defn parity [coll]
  (->> coll
       frequencies
       (filter (fn [[_ v]] (odd? v)))
       (map first)
       set))

例如,

(parity [1 1 1 2 1 2 1 3])
;#{1 3}

如何使用clojure reduce功能完成此操作。

我们可以使用reduce重写frequencies

(defn frequencies [coll]
  (reduce
   (fn [acc x] (assoc acc x (inc (get acc x 0))))
   {}
   coll))

......并再次实施parity

(defn parity [coll]
  (let [freqs (frequencies coll)]
    (reduce (fn [s [k v]] (if (odd? v) (conj s k) s)) #{} freqs)))