snippetMinor
Generate a deck of cards in Clojure / Clojurescript
Viewed 0 times
clojurecardsdeckgenerateclojurescript
Problem
I would like to generate a deck of cards:
And here is my attempt:
The code works but I think it is awkward. Especially the part where I use
Any suggestions to improve the code snippet?
{:card-id 1 :suit :spade :rank 1}
{:card-id 2 :suit :spade :rank 2}
...
{:card-id 52 :suit :club :rank 13}And here is my attempt:
(defn new-deck []
(let [cards (flatten
(for [suit [:spade :heart :diamond :club]]
(for [rank [1 2 3 4 5 6 7 8 9 10 11 12 13]]
{:suit suit :rank rank} )))]
(map-indexed (fn [idx itm] {:card-id (inc idx)
:suit (:suit itm)
:rank (:rank itm)})
cards)))The code works but I think it is awkward. Especially the part where I use
map-indexed function to add :card-id to each card.Any suggestions to improve the code snippet?
Solution
There are a few minor improvements you can make here that lead to a fairly elegant implementation.
First, using
However, as @ChrisMurphy points out, the
Then, instead of writing out the full range of numbers from 1 to 13, you can use the
Finally, rather than manually deconstructing and reconstructing each map in your lambda that you pass to
With these changes, you end up with a solution that looks like this:
First, using
flatten is rarely a good idea, because rather than just dealing with the top-level structure of the thing you hand it, it reaches down into its inner structure, thus making it brittle when you change the representation of your data. Therefore, you should instead use apply concat in place of flatten in your code.However, as @ChrisMurphy points out, the
for macro already supports list products, so you can replace the usage of flatten or apply concat and the two usages of for with a single usage of for that produces a flat sequence.Then, instead of writing out the full range of numbers from 1 to 13, you can use the
range function to replace that vector with (range 1 (inc 13)) or something equivalent.Finally, rather than manually deconstructing and reconstructing each map in your lambda that you pass to
map-indexed, you can use the assoc function to simply add the :card-id mapping.With these changes, you end up with a solution that looks like this:
(defn new-deck []
(map-indexed
#(assoc %2 :card-id (inc %1))
(for [suit [:spade :heart :diamond :club]
rank (range 1 (inc 13))]
{:suit suit :rank rank})))Code Snippets
(defn new-deck []
(map-indexed
#(assoc %2 :card-id (inc %1))
(for [suit [:spade :heart :diamond :club]
rank (range 1 (inc 13))]
{:suit suit :rank rank})))Context
StackExchange Code Review Q#157827, answer score: 7
Revisions (0)
No revisions yet.