Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Loops 使用传递值运行嵌套循环的惯用方法_Loops_Clojure_Nested Loops_Idioms_Code Translation - Fatal编程技术网

Loops 使用传递值运行嵌套循环的惯用方法

Loops 使用传递值运行嵌套循环的惯用方法,loops,clojure,nested-loops,idioms,code-translation,Loops,Clojure,Nested Loops,Idioms,Code Translation,我想做这样的事情 int n=0 for(int i=xs; i<xe; i++){ for(int j=ys; j<ye; j++){ n++ } } return n; 以Clojure的方式。因为所有的值都是不可变的,所以我认为值n应该作为可能的递归函数的参数传递。这样做的最佳方法是什么?不要过度考虑这个问题。当您确实需要可变状态时,始终可以使用atom: 结果 (calc xs ys) => 138 你也可以用一个。它就像一个非线程安全的原子。请注意

我想做这样的事情

int n=0
for(int i=xs; i<xe; i++){
  for(int j=ys; j<ye; j++){
    n++
  }
}
return n;

以Clojure的方式。因为所有的值都是不可变的,所以我认为值n应该作为可能的递归函数的参数传递。这样做的最佳方法是什么?

不要过度考虑这个问题。当您确实需要可变状态时,始终可以使用atom:

结果

(calc xs ys) => 138
你也可以用一个。它就像一个非线程安全的原子。请注意vswap的使用!:

表演 在一个紧密的循环中,使用volatile会有所不同。例如:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [tupelo.profile :as prof]))

(def N 100)
(def vals (vec (range N)))

(prof/defnp summer-atom []
  (let [result (atom 0)]
    (doseq [i vals]
      (doseq [j vals]
        (doseq [k vals]
          (swap! result + i j k))))
    @result))

(prof/defnp summer-volatile []
  (let [result (volatile! 0)]
    (doseq [i vals]
      (doseq [j vals]
        (doseq [k vals]
          (vswap! result + i j k))))
    @result))

(dotest
  (prof/timer-stats-reset)
  (dotimes [i 10]
    (spyx (summer-atom))
    (spyx (summer-volatile)))
  (prof/print-profile-stats))
结果:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 15
--------------------------------------

Testing tst.demo.core

(summer-atom)     => 148500000
(summer-volatile) => 148500000
...

---------------------------------------------------------------------------------------------------
Profile Stats:
   Samples       TOTAL        MEAN      SIGMA           ID
       10        2.739     0.273879   0.023240   :tst.demo.core/summer-atom                                                       
       10        0.383     0.038313   0.041246   :tst.demo.core/summer-volatile                                                   
---------------------------------------------------------------------------------------------------
因此,它产生了大约10倍的差异。可能不值得,除非你正在做至少100万次这样的操作

有关数据结构的类似低级操作,请参阅和朋友


尤其是把Clojure的备忘单加上书签

不要想太多问题。当您确实需要可变状态时,始终可以使用atom:

结果

(calc xs ys) => 138
你也可以用一个。它就像一个非线程安全的原子。请注意vswap的使用!:

表演 在一个紧密的循环中,使用volatile会有所不同。例如:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [tupelo.profile :as prof]))

(def N 100)
(def vals (vec (range N)))

(prof/defnp summer-atom []
  (let [result (atom 0)]
    (doseq [i vals]
      (doseq [j vals]
        (doseq [k vals]
          (swap! result + i j k))))
    @result))

(prof/defnp summer-volatile []
  (let [result (volatile! 0)]
    (doseq [i vals]
      (doseq [j vals]
        (doseq [k vals]
          (vswap! result + i j k))))
    @result))

(dotest
  (prof/timer-stats-reset)
  (dotimes [i 10]
    (spyx (summer-atom))
    (spyx (summer-volatile)))
  (prof/print-profile-stats))
结果:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 15
--------------------------------------

Testing tst.demo.core

(summer-atom)     => 148500000
(summer-volatile) => 148500000
...

---------------------------------------------------------------------------------------------------
Profile Stats:
   Samples       TOTAL        MEAN      SIGMA           ID
       10        2.739     0.273879   0.023240   :tst.demo.core/summer-atom                                                       
       10        0.383     0.038313   0.041246   :tst.demo.core/summer-volatile                                                   
---------------------------------------------------------------------------------------------------
因此,它产生了大约10倍的差异。可能不值得,除非你正在做至少100万次这样的操作

有关数据结构的类似低级操作,请参阅和朋友


尤其是将Clojure备忘单标记为书签,最接近您的代码的是

(defn f [xs xe ys ye]
  (let [n (atom 0)]
    (doseq [_ (range xs xe)
            _ (range ys ye)]
      (swap! n inc))
    @n))

user> (f 1 10 2 20)
;;=> 162
但是,可变原子方法是完全不符合实际的

它可能看起来像这样,有点像clojure的方式:

这取决于你想做什么。@jas注意到,*-xexs-yeys显然可以更好地计算n,这与您使用的语言无关

那么您提到的递归解决方案呢,它可能是这样的:

(defn f [xs xe ys ye]
  (loop [n 0 i xs j ys]
    (cond (== j ye) n
          (== i xe) (recur n xs (inc j))
          :else (recur (inc n) (inc i) j))))
#'user/f

user> (f 1 10 2 20)
;;=> 162
(def xs 0)
(def xe 9)
(def ys 1)
(def ye 4)

(for-state
 i xs (< i xe) (inc i) n 0
 (for-state
  j ys (< j ye) (inc j) n n
  (inc n)))
;; => 27

最接近您的代码是

(defn f [xs xe ys ye]
  (let [n (atom 0)]
    (doseq [_ (range xs xe)
            _ (range ys ye)]
      (swap! n inc))
    @n))

user> (f 1 10 2 20)
;;=> 162
但是,可变原子方法是完全不符合实际的

它可能看起来像这样,有点像clojure的方式:

这取决于你想做什么。@jas注意到,*-xexs-yeys显然可以更好地计算n,这与您使用的语言无关

那么您提到的递归解决方案呢,它可能是这样的:

(defn f [xs xe ys ye]
  (loop [n 0 i xs j ys]
    (cond (== j ye) n
          (== i xe) (recur n xs (inc j))
          :else (recur (inc n) (inc i) j))))
#'user/f

user> (f 1 10 2 20)
;;=> 162
(def xs 0)
(def xe 9)
(def ys 1)
(def ye 4)

(for-state
 i xs (< i xe) (inc i) n 0
 (for-state
  j ys (< j ye) (inc j) n n
  (inc n)))
;; => 27

我想在这里你可以应用reduce函数。循环内处理fn的工作由您决定——它也可以是递归的

(let [n-init 0 ;; your `n` variable
      xs 10 xe 20 ys -5 ye 5 ;; loop(s) ranges
      loop-processing-fn (fn [current-state [i j :as loop-data]]
                           (inc current-state) ;; anything here 
                           ) ;; processing function operating on state (n) and loop data

      ]
  (reduce loop-processing-fn n-init (for [i (range xs xe)
                                          j (range ys ye)]
                                      [i j])))
;; => 100

我想在这里你可以应用reduce函数。循环内处理fn的工作由您决定——它也可以是递归的

(let [n-init 0 ;; your `n` variable
      xs 10 xe 20 ys -5 ye 5 ;; loop(s) ranges
      loop-processing-fn (fn [current-state [i j :as loop-data]]
                           (inc current-state) ;; anything here 
                           ) ;; processing function operating on state (n) and loop data

      ]
  (reduce loop-processing-fn n-init (for [i (range xs xe)
                                          j (range ys ye)]
                                      [i j])))
;; => 100

我想到了宏。我为状态定义了一个宏,如下所示:

(defn f [xs xe ys ye]
  (loop [n 0 i xs j ys]
    (cond (== j ye) n
          (== i xe) (recur n xs (inc j))
          :else (recur (inc n) (inc i) j))))
#'user/f

user> (f 1 10 2 20)
;;=> 162
(def xs 0)
(def xe 9)
(def ys 1)
(def ye 4)

(for-state
 i xs (< i xe) (inc i) n 0
 (for-state
  j ys (< j ye) (inc j) n n
  (inc n)))
;; => 27

你可以随意调整。例如,您可以使用向量对宏参数进行分组,并对这些参数进行解构以提高可读性。

想到宏。我为状态定义了一个宏,如下所示:

(defn f [xs xe ys ye]
  (loop [n 0 i xs j ys]
    (cond (== j ye) n
          (== i xe) (recur n xs (inc j))
          :else (recur (inc n) (inc i) j))))
#'user/f

user> (f 1 10 2 20)
;;=> 162
(def xs 0)
(def xe 9)
(def ys 1)
(def ye 4)

(for-state
 i xs (< i xe) (inc i) n 0
 (for-state
  j ys (< j ye) (inc j) n n
  (inc n)))
;; => 27

你可以随意调整。例如,您可以使用向量对宏参数进行分组,并对这些参数进行解构以提高可读性。

这难道不只是返回*-xe xs-ye ys吗?如果您计划在内部循环体中执行比n++更有趣的操作,答案可能取决于该操作是否有副作用,例如打印,或者是构建某种类型的新集合,还是转换现有集合等等。在大多数情况下,您可以通过使用高阶函数来避免递归。@jas是的,根据本例就是这样。实际上,n++操作是不同的,要复杂得多。关键是如何在嵌套递归中将变量n传递给参数。仅举一个例子,请参阅,但如果不了解更多有关您尝试执行的操作,则很难说更多。这难道不只是返回*-xe xs-ye ys吗?如果您计划在内部循环体中执行比n++更有趣的操作,答案很可能取决于这件事是否有副作用,例如打印,或者是否要构建某种新集合,或者转换现有集合等。在大多数情况下,您可以通过使用高阶函数避免递归。@jas是的,根据本例就是这样。实际上,n++操作是不同的,要复杂得多。关键是如何在嵌套递归中将变量n交给参数。仅举一个例子,请参阅,但如果不了解更多有关您尝试执行的操作,则很难说得更多。我认为最后一个循环示例最接近问题的实质,在Clojure中,这是一件非常自然的事情。我认为最后一个循环示例最接近问题的精神,在Clojure中,这是一件非常自然的事情。