I am writing a slack bot that can take a group of people and the office that they work for and then break them into n random groups, making sure to mix the two offices together.
I have a few functions that do this just fine, but I am wondering if there is a more "Clojure" way to do this? I am still trying to break out of my object-oriented habits so any suggestions are very welcome.
My thought for this approach was to treat this like a deck of cards and deal the people out into each resulting group until I run out of people in an office, then move to the next one until I run out of offices then return my result.
(defn split
"split by office then shuffle
result is sorted by size"
[coll]
(->> (sort-by :office coll)
(partition-by :office)
(sort-by count)
(map shuffle)))
(defn conj-in
"inserts an item into a collection's child"
[coll idx itm]
(assoc coll idx (conj (nth coll idx) itm)))
(defn split-into-groups
[coll]
(let [sorted (split coll)]
(loop [pool (rest sorted)
hand (first sorted)
result (into [] (take @ngroups (repeat [])))
idx 0]
(if (not-empty hand)
(let [next (first hand)]
(recur pool
(rest hand)
(conj-in result idx next)
(mod (inc idx) @ngroups)))
(if (not-empty pool)
(recur (rest pool)
(first pool)
result
idx)
result)))))