Jeff Spaulding
Jeff Spaulding

Reputation: 223

Where is this list coming from in Clojure?

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:

  1. Where is this extra level of nesting coming from? I've tried various versions of cons, concat, list, etc. to no avail.
  2. What can I do to make this more "Clojury?"

Upvotes: 2

Views: 76

Answers (1)

birdspider
birdspider

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

Related Questions