HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Enumerate k-combinations in Clojure (P26 from 99 problems)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
clojurecombinationsp26problemsfromenumerate

Problem

I've been playing with Clojure for the last few evenings, going through the well known 99 problems (I'm using a set adapted for Scala).


Problem 26


Given a set S and a no. of items K, returns all possible
combinations of K items that can be taken from set S.

Here's my solution:

(defn combinations [k s]
  (cond
    (> k (count s)) nil        ;not enough items in sequence to form a valid combination
    (= k (count s)) [s]        ;only one combination available: all items 
    (= 1 k) (map vector s)     ;every item (on its own) is a valid combination
    :else (reduce concat (map-indexed 
            (fn [i x] (map #(cons x %) (combinations (dec k) (drop (inc i) s)))) 
            s))))

(combinations 3 ['a 'b 'c 'd 'f])


My basic solution is to take each item from the given sequence (map-indexed) and recurse to generate combinations of size K - 1 from the remaining sequence. The termination conditions are described above.

I'm still a complete Clojure newbie and would welcome comments on structure, efficiency, readability, resemblance to idiomatic Clojure, etc. Feel free to be brutal, but please remember I've been doing Clojure for only a few hours :)

I'm less interested in alternative mathematical methods for generating k-combinations, more interested in feedback on whether this is passable Clojure.

Solution

I'm currently reading "Joy of Clojure" so I'm (very) far from being "fluent" in Clojure but what I noticed is:

  • your solution is clever but quite complicated, you use "imperative" habits like indexed iteration



  • try to keep with simple abstractions like sequence first and rest and the solution will work with any Clojure collection - see example below



  • your solution use cond with three checks for k - consider using condp



Here's my code:

(defn subsets [n items]
(cond
    (= n 0) '(())
    (empty? items) '()
    :else (concat (map
                    #(cons (first items) %)
                    (subsets (dec n) (rest items)))
                  (subsets n (rest items)))))

Code Snippets

(defn subsets [n items]
(cond
    (= n 0) '(())
    (empty? items) '()
    :else (concat (map
                    #(cons (first items) %)
                    (subsets (dec n) (rest items)))
                  (subsets n (rest items)))))

Context

StackExchange Code Review Q#8930, answer score: 3

Revisions (0)

No revisions yet.