簡體   English   中英

clojure中的除數函數

[英]Divisor function in clojure

我是clojure的新手,我想創建一個函數,它返回某個Number的所有除數的向量。

例如:
[1 2 3]為6作為輸入

(defn div [x seq]
  (let [r  (range 1 (+ (/ x 2) 1)) ]   
    (dotimes [i (count (range 1 (+ (/ x 2) 1) ))]      
     (cond
      (= (mod x (nth r i )) 0)(print (conj  seq (nth r i ))) 
     ))))

此函數以以下格式返回輸出:
[1] [2] [4] [5] [10] [20] [25] [50]為100,但我想在一個向量中得到輸出。 似乎seq變量不斷被每個循環步驟覆蓋。 誰能解釋這種行為並為我提供一個解決方法?

在此先感謝您的問候

您可以使用更慣用的解決方案來避免循環:

(defn divisors 
  [n]
  (filter (comp zero? (partial rem n)) (range 1 n)))

我認為你的方法不正確,你可以看看:

  • 循環函數來解決這類問題(我的意思是你需要迭代和屈服值的情況),
  • 迭代函數
  • 遞歸函數(一個自我調用的函數)

此代碼(使用' for '函數)可以輕松解決您的規范

(let [n 100]
  (for [x (range 1 n)
       :when (zero? (rem n x))]
   x))
=>(1 2 4 5 10 20 25 50)

您的根本問題是您正在嘗試采用命令式方法,但Clojure集合是不可變的。 此外,我認為dotimes將始終返回nil ,並且print在打印其參數后返回nil

有一種更好的方法,但讓我們首先看看我們如何使用原子來獲得一個必要的解決方案:

(defn div [x seq]
  (let [r  (range 1 (+ (/ x 2) 1)) ]   
    (dotimes [i (count (range 1 (+ (/ x 2) 1) ))]      
      (cond
       ;; "Append" the ith element of r to seq
       ;; (Technically, we are replacing the value stored in seq
       ;; with a new list -- the result of conj-ing (nth r i)
       ;; to the current value stored in seq)
       (= (mod x (nth r i )) 0) (swap! seq conj (nth r i )))))  ;; <= don't print
  seq) ;; <== seq is what we're interested in, so we return it here.
       ;;     Otherwise, we would return the result of dotimes,
       ;;     which is nil

請注意,我們已經消除了print並期望seq成為一個原子(我們使用swap!更新swap! )。 我們現在可以調用div如下:

user> (deref (div 6 (atom [])))
[1 2 3]

我們可以通過運動改善這種seq從參數列表, let里面的函數,然后取消引用它,當我們返回。 但最好首先避免變異。 正如七巧板在他的回答中指出的那樣,這很容易for

(defn div [x]
  (let [r (range 1 (+ (/ x 2) 1))]
    ;; Loop over r, taking only elements that are divisors of x
    (for [i r
          :when (= (mod x i) 0)]
      i))) ;; <= for accumulates the result of this expression (here simply i) into a sequence

user> (div 6)
(1 2 3)

在生產代碼中,您可能會在這種情況下內聯r ,但我希望盡可能保留原始結構。 我們也可以使用zero? :when子句中。 但是我們在for循環中真正做的只是一個簡單的過濾器,所以我們可以采用Guillermo的方法並使用filter

div將整數x和序列seq作為參數:

  • 它首先聲明r范圍1..(x/2) ;

  • 然后迭代i0(count r) ,即從0(x/2) - 1

    • 對於每個i ,它打印(conj seq (nth ri))的結果,即(conj seq (+ i 1))

      Clojure使用不可變數據結構,這意味着(conj seq d)返回一個包含所有seq元素加d的新序列; 特別是,如果seq是空向量[] ,則返回[d]

最終結果: (div n [])如果d除以x則打印[d] ,每個d1(x/2)

您的代碼失敗,因為您嘗試以命令方式編寫Clojure代碼; 它不是標准的(也不推薦),但可以通過使用可變引用,例如原子 (參見@NathanDavis的答案 )或瞬態 (可變)數據結構:

(defn div [n]
  (let [coll (transient [])]
    (dotimes [i (quot n 2)]
      (let [d (inc i)]
        (when (zero? (rem n d))
          (conj! coll d))))
    (persistent! coll)))

一個慣用的解決方案將for (如@tangrammer 建議 ); 它不是一個循環結構(就像在Java中一樣),而是一個返回延遲序列的宏:

(defn div [n]
  (for [:let [from 1                  ;; :let bindings are great for
              upto (inc (quot n 2))   ;; readability
              divides? #(zero?
                         (rem % %2))]

        d (range from upto)           ;; This binding form translates to
                                      ;; "each d from 1 to x/2".
                                      ;; You can have several binding forms
                                      ;; in a single for, to iterate over
                                      ;; several variables.

        :when (divides? n d)]         ;; Selects d only if it divides n.
                                      ;; You can also define termination
                                      ;; conditions with :while.

    d))                               ;; Each valid d is appended to a growing
                                      ;; lazy sequence i.e. a sequence that is
                                      ;; constructed the first time it is
                                      ;; traversed.

for沒有身體可言的形式感覺有點辱罵(雖然賞心悅目,恕我直言); 另一種選擇是@GuillermoWinkler回答中顯示的過濾器:

(defn divisors 
  [n]
  (->> (range 1 (inc (quot n 2)))     ;; the threading macros ->, ->> and .. are
       (filter #(zero? (rem n %)))))  ;; great to write sequence-manipulation
                                      ;; code as a sequence of step, though
                                      ;; maybe overkill in the present case

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM