(Sent the below email earlier but for some reason didn't make it to the list)

I wasn't aware of the group-by function. Being new to clojure, I spent a lot of 
time coming up with my complex function. Seeing the one line solution really 
blew me away. Thanks!!

Follow up questions on my problem (my code again first):

;data is a list of records (maps)
(def data '({:a1 2 :a2 34 :a3 76 :a4 87}, 
            {:a1 3 :a2 30 :a3 38 :a4 39}, 
            {:a1 2 :a2 67 :a3 32 :a4 38}, 
            {:a1 4 :a2 47 :a3 73 :a4 38}, 
            {:a1 3 :a2 84 :a3 86 :a4 63}))

;result is a map, key = value of :a1, val = all records for that value of a1
;as pointed out, result can be obtained by (group-by :a1 data)
(def result 
  '{2 [{:a1 2 :a2 34 :a3 76 :a4 87}, {:a1 2 :a2 67 :a3 32 :a4 39}], ;grouped a1 
= 2
    3 [{:a1 3 :a2 30 :a3 38 :a4 39}, {:a1 3 :a2 84 :a3 86 :a4 63}], ;grouped a1 
= 3
    4 [{:a1 4 :a2 47 :a3 73 :a4 38}] ;grouped :a1 = 4
   })

;groups the data by :a1 (see result above)
(def data-g (group-by :a1 data)

;for a key value in data-g returns the total of all :a4 values
(defn calc-tot-a4 [data-g k]
  (reduce + (map :a4 (get data-g k))))

;adjust a4 values for a given key
(defn adj-a4 [data k]
  (assoc data k (map #(assoc % :a4 (+ (:a3 %) (:a4 %))) (get data k))))

;adjust data
(defn adj-data [data f]
  (reduce f data (keys data)))

;make adjustments to the grouped data
(def data-adj (adj-data data-g adj-a4))

I am expressing my domain specific problem in a very abstract way above. In 
reality the data I am manipulating comes from a database. This is financial 
performance data for an entire month. The data set is large - about 50,000 
records. I need to group it by "day" and then perform manipulations on it. For 
example, I need to make adjustments to the values loaded from the database 
based on certain conditions. I need to aggregate values for a certain day etc.

My question is - am I on the right track with the adj-data/adj-a4 functions. 
Secondly since I am constantly modifying the in-memory data (loaded using 
contrib.sql functions which loads it into plain maps), is this inefficient 
since the data structures are immutable. So every time I change a value, 
clojure functions will return me a new data structure. Will this be inefficient 
when I am dealing with a large data set and making constant 
modifications/adjustments to the values?

Thanks for your great help.

-----Original Message-----
From: clojure@googlegroups.com [mailto:clojure@googlegroups.com] On Behalf Of 
Alan
Sent: Sunday, April 17, 2011 5:18 PM
To: Clojure
Subject: Re: Help with function to partition my data

Simpler still: group-by?

(group-by :a1 data) produces the result that Shoeb was looking for.

PS The original message isn't in Google's archives either.


On Apr 17, 7:54 am, Nate Austin <navis...@gmail.com> wrote:
> I didn't see this original email for some reason, but here's a
> simplified version:
>
> (reduce
>   (fn [coll {a1 :a1 :as value}] (update-in coll [a1] conj value))
>   {}
>   data)
>
> This takes advantage of update-in passing nil if it doesn't have the
> key and conj with nil returning a seq of one value.
>
>
>
>
>
>
>
> On Sun, Apr 17, 2011 at 12:30 AM, Shoeb Bhinderwala <shua...@gmail.com> wrote:
> > Wrote the following function which did the trick:
>
> > (defn partn [data]
> >   (let
> >     [add-mapping
> >       (fn [m v]
> >         (assoc m v (filter #(= v (:a1 %)) data)))]
> >     (reduce add-mapping {} (set (map #(:a1 %) data))))
>
> > On Sat, Apr 16, 2011 at 8:15 PM, shuaybi <shua...@gmail.com> wrote:
>
> >> I am trying to write a function but can't get it right. I need to loop
> >> through my data records and for each unique value of :a1 I need to
> >> partition the data and create a resulting map so that the key is value
> >> of :a1 and the associated value of this key is all records with that
> >> value of :a1. Better explained with code, where given the definition
> >> of data below, I need to write a function that will return the
> >> definition of "result" below.
>
> >> ;data is a list of records (maps)
> >> (def data '({:a1 2 :a2 34 :a3 76 :a4 87},
> >>            {:a1 3 :a2 30 :a3 38 :a4 39},
> >>            {:a1 2 :a2 67 :a3 32 :a4 38},
> >>            {:a1 4 :a2 47 :a3 73 :a4 38},
> >>            {:a1 3 :a2 84 :a3 86 :a4 63}))
>
> >> ;result should be a map, keyed by unique values of :a1 and containing
> >> all records for that value of :a1
> >> (def result '{2 ({:a1 2 :a2 34 :a3 76 :a4 87}, {:a1 2 :a2 67 :a3
> >> 32 :a4 39}), ;list of records where :a1 = 2
> >>              3 ({:a1 3 :a2 30 :a3 38 :a4 39}, {:a1 3 :a2 84 :a3
> >> 86 :a4 63}), ;list of records where :a1 = 3
> >>              4 ({:a1 4 :a2 47 :a3 73 :a4 38}) ;list of records
> >> where :a1 = 4
> >>              })
>
> >> (defn get-val-a1
> >>  "Return all records in data where :a1 is specified val"
> >>  [data val]
> >>  (filter
> >>    #(= val (:a1 %)) ;filter function
> >>    data))
>
> >> (defn unique-a1
> >>  "Get set of all unique :a1 values"
> >>  [m]
> >>  (set (map #(:a1 %) m)))
>
> >> ;This is the function I am trying to write but can't get it right.
> >> (defn partn [data]
> >>  (let [val-set (unique-a1 data)) ;get unique :a1 values
> >>        ret-val {}]
> >>    (loop [v val-set] ;loop through the unique values
> >>      (assoc ret-val v (get-val-a1 data v))) ;build final map
> >>    ret-val))
>
> > --
> > 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

-- 
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

-- 
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