My goal is to simulate a Pile shuffle of a vector. It takes 2 optional arguments for the number of piles to use and how many times to perform the shuffle.

As this is my first attempt at clojure code, I'm fairly sure I'm doing something terribly wrong here. I'm concerned with speed, efficiency, and indentation style. I'd also appreciate any pointers that would make this function more generic (maybe not restricting to vectors, but general collections).

(defn pile
  ([cards] (pile cards 3 1))
  ([cards num_piles] (pile cards num_piles 1))
  ([cards num_piles times]
    (loop [i 1
           piles (transient (vec (map (fn [p] []) (range num_piles))))
           the_pile 0]
      (if (<= i (count cards))
        (recur (inc i)
                 (vec (concat [(nth cards (dec i))]
                               (nth piles the_pile))))
               (rem i num_piles))
        (if (> times 1)
          (pile (reduce into (persistent! piles)) num_piles (dec times) )
          (vec (reduce into (persistent! piles))))))))

You need loop/recur very rarely in most code, and almost never for operating on collections/sequences. Using the standard library sequence functions, it’s possible to do the main pile shuffle with just a handful of expressions:

(->> (range (dec n) -1 -1) (mapcat #(take-nth n (drop % cards))) reverse)

It takes some getting used to, and familiarity with the Clojure standard library. When I was first getting started, I found it immensely helpful to read the clojure/core.clj code. It isn’t all idiomatic because it’s building the support for the idioms as it goes, but it demonstrates what Clojure makes possible and how it makes those things possible.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.