Dmitry Kakurin wrote:
> I actually like your "tag them then group them" approach.
> But what if the same record can have multiple tags?
> E.g. :sales and :upgrades?
> 

Hmmm. the first way that occurred to me is just make your tagging 
function return a set:

(defn record-types [x]
  (disj
   #{(when (is-sale? x) :sales)
     (when (is-upgrade? x) :upgrades)
     (when (is-demo? x) :demos)}
   nil))

So you'd then get groups like:

{#{:sales :upgrades} [...]
  #{:sales}           [...]
  #{:upgrades}        [...]}

But unfortunately it seems that because the group-by in 
clojure.contrib.seq-utils uses a sorted-map it can't have keys that are 
sets (as there's no ordering defined for sets).  You could either use 
vectors instead of sets, or better yet lets just define reduce-by and 
group-by to use a hash-map instead:

(defn reduce-by [grouper f val coll]
    (reduce (fn [m x]
              (let [group (grouper x)]
                (assoc m group (f (get m group val) x))))
            {} coll))

(defn group-by [grouper coll]
   (reduce-by grouper conj [] coll))

This has the advantage that you can do things like intersections 
("number of sales sales that were also upgrades").  If you don't care 
about intersections and just want the three :sales, :upgrades, and 
:demos lists, then I guess we start with 'for' to generate [tag record] 
pairs:

(for [record (get-idata)
       type (record-types record)]
   [type record])

So if "data1" is both sales and upgrades then you'd get:

   ([:sales data1] [:upgrades data1] [:sales data2] [:demos data3] ...)

We can then reduce-by grouped on the first value in the pair (the tag) 
and then transform the resulting maps to select just the second item in 
the pair (the record):

(reduce-by
  first #(conj %1 (second %2)) []
  (for [record (get-idata)
        type (record-types record)]
    [type record]))

=> {:sales [data1 data2 ... ],
     :upgrades [data1 data3 ...],
     :demos [data4 ...]}

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to