diff src/clojure/set.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/clojure/set.clj	Sat Aug 21 06:25:44 2010 -0400
     1.3 @@ -0,0 +1,177 @@
     1.4 +;   Copyright (c) Rich Hickey. All rights reserved.
     1.5 +;   The use and distribution terms for this software are covered by the
     1.6 +;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
     1.7 +;   which can be found in the file epl-v10.html at the root of this distribution.
     1.8 +;   By using this software in any fashion, you are agreeing to be bound by
     1.9 +;   the terms of this license.
    1.10 +;   You must not remove this notice, or any other, from this software.
    1.11 +
    1.12 +(ns ^{:doc "Set operations such as union/intersection."
    1.13 +       :author "Rich Hickey"}
    1.14 +       clojure.set)
    1.15 +
    1.16 +(defn- bubble-max-key [k coll]
    1.17 +  "Move a maximal element of coll according to fn k (which returns a number) 
    1.18 +   to the front of coll."
    1.19 +  (let [max (apply max-key k coll)]
    1.20 +    (cons max (remove #(identical? max %) coll))))
    1.21 +
    1.22 +(defn union
    1.23 +  "Return a set that is the union of the input sets"
    1.24 +  {:added "1.0"}
    1.25 +  ([] #{})
    1.26 +  ([s1] s1)
    1.27 +  ([s1 s2]
    1.28 +     (if (< (count s1) (count s2))
    1.29 +       (reduce conj s2 s1)
    1.30 +       (reduce conj s1 s2)))
    1.31 +  ([s1 s2 & sets]
    1.32 +     (let [bubbled-sets (bubble-max-key count (conj sets s2 s1))]
    1.33 +       (reduce into (first bubbled-sets) (rest bubbled-sets)))))
    1.34 +
    1.35 +(defn intersection
    1.36 +  "Return a set that is the intersection of the input sets"
    1.37 +  {:added "1.0"}
    1.38 +  ([s1] s1)
    1.39 +  ([s1 s2]
    1.40 +     (if (< (count s2) (count s1))
    1.41 +       (recur s2 s1)
    1.42 +       (reduce (fn [result item]
    1.43 +                   (if (contains? s2 item)
    1.44 +		     result
    1.45 +                     (disj result item)))
    1.46 +	       s1 s1)))
    1.47 +  ([s1 s2 & sets] 
    1.48 +     (let [bubbled-sets (bubble-max-key #(- (count %)) (conj sets s2 s1))]
    1.49 +       (reduce intersection (first bubbled-sets) (rest bubbled-sets)))))
    1.50 +
    1.51 +(defn difference
    1.52 +  "Return a set that is the first set without elements of the remaining sets"
    1.53 +  {:added "1.0"}
    1.54 +  ([s1] s1)
    1.55 +  ([s1 s2] 
    1.56 +     (if (< (count s1) (count s2))
    1.57 +       (reduce (fn [result item] 
    1.58 +                   (if (contains? s2 item) 
    1.59 +                     (disj result item) 
    1.60 +                     result))
    1.61 +               s1 s1)
    1.62 +       (reduce disj s1 s2)))
    1.63 +  ([s1 s2 & sets] 
    1.64 +     (reduce difference s1 (conj sets s2))))
    1.65 +
    1.66 +
    1.67 +(defn select
    1.68 +  "Returns a set of the elements for which pred is true"
    1.69 +  {:added "1.0"}
    1.70 +  [pred xset]
    1.71 +    (reduce (fn [s k] (if (pred k) s (disj s k)))
    1.72 +            xset xset))
    1.73 +
    1.74 +(defn project
    1.75 +  "Returns a rel of the elements of xrel with only the keys in ks"
    1.76 +  {:added "1.0"}
    1.77 +  [xrel ks]
    1.78 +    (set (map #(select-keys % ks) xrel)))
    1.79 +
    1.80 +(defn rename-keys
    1.81 +  "Returns the map with the keys in kmap renamed to the vals in kmap"
    1.82 +  {:added "1.0"}
    1.83 +  [map kmap]
    1.84 +    (reduce 
    1.85 +     (fn [m [old new]]
    1.86 +       (if (and (not= old new)
    1.87 +                (contains? m old))
    1.88 +         (-> m (assoc new (get m old)) (dissoc old))
    1.89 +         m)) 
    1.90 +     map kmap))
    1.91 +
    1.92 +(defn rename
    1.93 +  "Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap"
    1.94 +  {:added "1.0"}
    1.95 +  [xrel kmap]
    1.96 +    (set (map #(rename-keys % kmap) xrel)))
    1.97 +
    1.98 +(defn index
    1.99 +  "Returns a map of the distinct values of ks in the xrel mapped to a
   1.100 +  set of the maps in xrel with the corresponding values of ks."
   1.101 +  {:added "1.0"}
   1.102 +  [xrel ks]
   1.103 +    (reduce
   1.104 +     (fn [m x]
   1.105 +       (let [ik (select-keys x ks)]
   1.106 +         (assoc m ik (conj (get m ik #{}) x))))
   1.107 +     {} xrel))
   1.108 +   
   1.109 +(defn map-invert
   1.110 +  "Returns the map with the vals mapped to the keys."
   1.111 +  {:added "1.0"}
   1.112 +  [m] (reduce (fn [m [k v]] (assoc m v k)) {} m))
   1.113 +
   1.114 +(defn join
   1.115 +  "When passed 2 rels, returns the rel corresponding to the natural
   1.116 +  join. When passed an additional keymap, joins on the corresponding
   1.117 +  keys."
   1.118 +  {:added "1.0"}
   1.119 +  ([xrel yrel] ;natural join
   1.120 +   (if (and (seq xrel) (seq yrel))
   1.121 +     (let [ks (intersection (set (keys (first xrel))) (set (keys (first yrel))))
   1.122 +           [r s] (if (<= (count xrel) (count yrel))
   1.123 +                   [xrel yrel]
   1.124 +                   [yrel xrel])
   1.125 +           idx (index r ks)]
   1.126 +       (reduce (fn [ret x]
   1.127 +                 (let [found (idx (select-keys x ks))]
   1.128 +                   (if found
   1.129 +                     (reduce #(conj %1 (merge %2 x)) ret found)
   1.130 +                     ret)))
   1.131 +               #{} s))
   1.132 +     #{}))
   1.133 +  ([xrel yrel km] ;arbitrary key mapping
   1.134 +   (let [[r s k] (if (<= (count xrel) (count yrel))
   1.135 +                   [xrel yrel (map-invert km)]
   1.136 +                   [yrel xrel km])
   1.137 +         idx (index r (vals k))]
   1.138 +     (reduce (fn [ret x]
   1.139 +               (let [found (idx (rename-keys (select-keys x (keys k)) k))]
   1.140 +                 (if found
   1.141 +                   (reduce #(conj %1 (merge %2 x)) ret found)
   1.142 +                   ret)))
   1.143 +             #{} s))))
   1.144 +
   1.145 +(defn subset? 
   1.146 +  "Is set1 a subset of set2?"
   1.147 +  {:added "1.2",
   1.148 +   :tag Boolean}
   1.149 +  [set1 set2]
   1.150 +  (and (<= (count set1) (count set2))
   1.151 +       (every? set2 set1)))
   1.152 +
   1.153 +(defn superset? 
   1.154 +  "Is set1 a superset of set2?"
   1.155 +  {:added "1.2",
   1.156 +   :tag Boolean}
   1.157 +  [set1 set2]
   1.158 +  (and (>= (count set1) (count set2))
   1.159 +       (every? set1 set2)))
   1.160 +
   1.161 +(comment
   1.162 +(refer 'set)
   1.163 +(def xs #{{:a 11 :b 1 :c 1 :d 4}
   1.164 +         {:a 2 :b 12 :c 2 :d 6}
   1.165 +         {:a 3 :b 3 :c 3 :d 8 :f 42}})
   1.166 +
   1.167 +(def ys #{{:a 11 :b 11 :c 11 :e 5}
   1.168 +         {:a 12 :b 11 :c 12 :e 3}
   1.169 +         {:a 3 :b 3 :c 3 :e 7 }})
   1.170 +
   1.171 +(join xs ys)
   1.172 +(join xs (rename ys {:b :yb :c :yc}) {:a :a})
   1.173 +
   1.174 +(union #{:a :b :c} #{:c :d :e })
   1.175 +(difference #{:a :b :c} #{:c :d :e})
   1.176 +(intersection #{:a :b :c} #{:c :d :e})
   1.177 +
   1.178 +(index ys [:b])
   1.179 +)
   1.180 +