Search code examples
loopsclojurenested-loopsidiomscode-translation

Idiomatic way to run nested loop with passing value


I want to do something like this

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

in Clojure way. Since all values are immutable, I think the value n should be passed as a parameter of a (possibly) recursive function. What is the best way to do so?


Solution

  • the closest to your code would be

    (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
    

    but the mutable atom approach is unidiomatic at all.

    it could look like this, a bit more clojure way:

    (defn f [xs xe ys ye]
      (count (for [_ (range xs xe)
                   _ (range ys ye)]
               nil)))
    #'user/f
    
    user> (f 1 10 2 20)
    ;;=> 162
    

    it really depends on what you're trying to do. Counting n's is obviously done better by (* (- xe xs) (- ye ys)) , as @jas noticed, independent from what language you use )

    what about recursive solution you mentioned, it could look like this:

    (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