Reputation: 223
I'm new to Clojure and fairly new to functional programming in general. I'm trying to create an anagram generator that produces all possible rearrangements of a string. I thought I'd generalize it and come up with all possible rearrangements of a list.
My attempt:
(defn pairs [items]
(list (list (first items) (last items))
(list (last items) (first items))))
(defn prepend-to-list-or-item [item coll]
(if (coll? coll)
(map #(cons item %) coll)
(list item coll)))
(defn remove-one [coll item]
(let [[n m]
(split-with (partial not= item) coll)]
(concat n (rest m))))
(defn get-combinations [items]
(cond (= 0 (count items)) nil
(= 1 (count items)) items
(= 2 (count items)) (pairs items)
:else
(map #(prepend-to-list-or-item % (get-combinations (remove-one items %))) items)))
The problem I'm having is that I'm getting lists that are nested too deeply. The output I'm getting is:
clojure-test.combinations> (clojure.pprint/pprint (get-combinations '(\a \b \c)))
(((\a \b \c) (\a \c \b))
((\b \a \c) (\b \c \a))
((\c \a \b) (\c \b \a)))
nil
My desired output:
((\a \b \c) (\a \c \b) (\b \a \c) (\b \c \a) (\c \a \b) (\c \b \a))
With more list items, the problem gets worse.
So, two questions:
Upvotes: 2
Views: 76
Reputation: 3074
try
:else
(mapcat #(
in get-combinations
Why:
(map list-producing-function a-list) ; will give you a list of lists
ad 2.)
I rephrased coll
to chars
and item
to char
- this was for my understanding only
you can simplify remove-one
(if I read it correctly you do want coll without item, which is exactly what filter
is for)
(defn remove-one [chars char]
(filter (partial not= char) chars))
get-combinations, more readable case statement
(let [char-count (count chars)]
(case char-count
0 nil
1 chars
2 (pairs chars)
(mapcat
Upvotes: 2