【发布时间】:2021-08-08 17:13:57
【问题描述】:
我有以下功能:
(defn next-transformation
[arr]
(let [
arr-len (count arr)
i-range (range 0 arr-len)
j-range (range 0 arr-len)
indexes (for [i i-range
j j-range]
(let [
xi (nth arr i)
xj (nth arr j)
]
(if (> xi xj)
[i j]
nil
)
)
)
non-nil-indexes (filter
(fn [elem]
(not (= elem nil))
)
indexes
)
]
(if (not (empty? non-nil-indexes))
(first non-nil-indexes)
nil
)
)
)
它返回元组数组[i j] 的第一个元素,该数组描述arr 数组中arr[i] > arr[j] 为真的元素。
下面片段中的 for 循环遍历每一对 i 和 j:
indexes (for [i i-range
j j-range]
(let [
xi (nth arr i)
xj (nth arr j)
]
(if (> xi xj)
[i j] ;; I want the loop to stop here
nil
)
)
)
如何修改这个 for 循环,使其在找到第一个相关元组后停止(即循环应该在标有;; I want the loop to stop here 注释的地方停止)?
这是Java中的等效代码:
private Integer[] next-transformation(final Integer[] arr) {
for (int i=0; i < arr.length; i++) {
for (int j=0; j < arr.length; j++) {
if (arr[i] > arr[j]) {
return new Integer[] {i, j};
}
}
}
}
更新 1:
按照@CharlesDuffy 的建议,我将for 替换为loop/recur:
(defn next-transformation
[arr]
(loop [i 0
j 0]
(let [
arr-len (count arr)
]
(if (and (< i arr-len)
(< j arr-len))
(let [
xi (nth arr i)
xj (nth arr j)
j-plus-1 (+ j 1)
i-plus-1 (+ i 1)
new-i (if (< j-plus-1 arr-len)
i
(+ i 1))
new-j (if (< j-plus-1 arr-len)
(+ j 1)
0)
]
(if (> xi xj)
;; We found it
[i j]
;; We haven't found it, recur
(recur new-i new-j)
)
)
nil ; We are at the end of the loop
) ; if
)
) ; loop
) ; defn
【问题讨论】:
-
Clojure 中的
for不应被视为循环。这是一个序列定义;它可以用于流量控制是一个副作用,而不是主要目的。 -
...也就是说,请参阅
:while内的for。 -
...无论如何,对于您的实际用例,我通常会选择
loop/recur,而不是for。为工作选择正确的工具,等等。 -
(另外,如果您在
for中使用:when,则无需让调用者负责跳过nils) -
for不像命令式语言中使用的循环结构,但它是一种“列表理解”。 Clojure 不是另一种底层语言的“LISP 转译器”,而是一种具有不可变数据结构的函数式编程语言。所以这是思维方式的一些转变,所以不要深入挖掘你“势在必行”的大脑区域来解决这样的问题。
标签: clojure