微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用传递值运行嵌套循环的惯用方式

如何解决用传递值运行嵌套循环的惯用方式

我想做这样的事情

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

用Clojure的方式。由于所有值都是不可变的,因此我认为值n应该作为(可能)递归函数的参数传递。最好的方法是什么?

解决方法

与您的代码最接近的是

(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方式:

(defn f [xs xe ys ye]
  (count (for [_ (range xs xe)
               _ (range ys ye)]
           nil)))
#'user/f

user> (f 1 10 2 20)
;;=> 162

这实际上取决于您要执行的操作。正如@jas所指出的,显然(* (- xe xs) (- ye ys))可以更好地计数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
,

不要过度思考问题。当您确实需要可变状态时,可以随时使用atom

(defn calc
  [xs ys]
  (let [result (atom 0)]
    (doseq [x xs]
      (doseq [y ys]
        (swap! result + (* x y))))
    @result))

  (let [xs     [1 2 3]
        ys     [2 5 7 9]]
    (calc xs ys))

有结果

(calc xs ys) => 138

您也可以使用volatile。它就像一个非线程安全的原子。请注意vswap!的使用:

(defn calc
  [xs ys]
  (let [result (volatile! 0)]
    (doseq [x xs]
      (doseq [y ys]
        (vswap! result + (* x y))))
    @result))

性能

在紧密循环中,使用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 ^ 3),否则可能不值得。

有关数据结构的类似低级操作,请参见transient!和朋友。

特别为Clojure CheatSheet from this list

添加书签 ,

我认为您可以在reduce上应用for函数。您在loop-processing-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
,

宏浮现在脑海。我定义了一个像这样使用的宏for-state

(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

宏使您可以添加仅使用函数难以构建的新结构。因此,如果您有几种此类的嵌套循环,则可以选择定义for-state之类的宏:

(defmacro for-state [iter-var iter-init iter? iter-next    
                     state-var state-init state-next]
  `(loop [~iter-var ~iter-init
          ~state-var ~state-init]
     (if ~iter?
       (recur ~iter-next
              ~state-next)
       ~state-var)))

您可以根据需要对其进行调整。例如,您可以使用向量对宏参数进行分组,并对这些参数进行解构以提高可读性。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?