繁体   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