16

I have created a very simple nested loop example and am struggling to write the equivalent Clojure code. I've been trying to do it by list comprehensions but cannot get the same answer. Any help appreciated.

public class Toy {

    public static void main(String[] args) {
        int maxMod = 0;
        for (int i=0;i<1000;i++) {
            for (int j=i;j<1000;j++) {
                if ((i * j) % 13 == 0 && i % 7 == 0) maxMod = i * j;
            }
        }
        System.out.println(maxMod);
    }
}
1
  • 6
    I guess this isn't the point of the exercise, but you can save a bunch of wasted work by incrementing i by seven at a time instead of 1. Commented Feb 4, 2012 at 3:02

3 Answers 3

25

Here's a list comprehension solution:

(last 
  (for [i (range 1000) 
        j (range 1000)
        :let [n (* i j)] 
        :when (and (= (mod n 13) 0) 
                   (= (mod i 7) 0))] 
    n))
Sign up to request clarification or add additional context in comments.

4 Comments

What's the difference between that and using doseq?
Don't you really just want the last entry, which we assume will also happen to be the maximum entry? In your expression above, the max function will keep trying to figure out if it's seen a new maximum for every element yielded by the for sequence.
@Bill for returns a lazy seq, while doseq executes the body howevery many times (presumably for side effects) and returns nil
By the way, nice job hoisting out the computation of n, which the original Java function failed to do.
9

In general, you want to use some sort of sequence operation (like dnolen's answer). However, if you need to do something that is not expressible in some combination of sequence functions, using the loop macro works as well. For this precise problem, dnolen's answer is better than anything using loop, but for illustrative purposes, here is how you would write it with loop.

(loop [i 0
       max-mod 0]
  (if (>= i 1000)
    (println max-mod)
    (recur (inc i)
           (loop [j 0
                  max-mod max-mod]
             (if (>= j 1000)
               max-mod
               (recur (inc j)
                      (if (and (= (mod (* i j) 13) 0)
                               (= (mod 1 7) 0))
                        (* i j)
                        max-mod)))))))

This is pretty much an exact translation of your given code. That said, this is obviously ugly, which is why a solution using for (or other similar functions) is preferred whenever possible.

Comments

2

List comprehensions create lists from other lists, but you want just a single value as result. You can create the input values (i and j) with a list comprehension, and then use reduce to get a single value from the list:

(reduce (fn [max-mod [i j]]
          (if (and (zero? (mod (* i j) 13))
                   (zero? (mod i 7)))
            (* i j)
            max-mod))
        0
        (for [i (range 1000) j (range 1000)]
             [i j]))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.