I have the following function:
(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
)
)
)
It returns the first element of an array of tuples [i j]
which describe elments of the array arr
for which arr[i] > arr[j]
is true.
The for
loop in the fragment below runs through every pair of i and 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
)
)
)
How can I modify this for loop so that it stops once it finds the first relevant tuple (i. e. the loop should stop at the place marked with ;; I want the loop to stop here
comment)?
Here is the equivalent code in 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};
}
}
}
}
Update 1:
As recommended by @CharlesDuffy, I replaced for
with 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
In the for
list comprehension, use :when
to filter for the tuples of interest, and use first
to return just the first one:
(defn next-transformation [arr]
(first (for [i (range (count arr))
j (range (count arr))
:when (> (nth arr i) (nth arr j))]
[i j])))