Reputation: 75
I am trying to iterate through a map to count specific occurances of individual events although I am having some trouble using a filter as below. What I want to do is filter and count the specific instances of each "ORDER_CATEGORY" which occur in a number of levels - 1, 2, and so on. I am able to iterate though the months and print but teh filter and count I have for the ORDER_CATEGORY's just doesnt seem to work for me.
GROUPED_BY_MONTH(group-by :MONTH CON)
ALL (for [flop GROUPED_BY_MONTH] {
:MONTH (:MONTH (first (second flop)))
:ORDER1 (count (filter #(= "1" (:ORDER_CATEGORY %)) flop))
:ORDER2 (count (filter #(= "2" (:ORDER_CATEGORY %)) flop))
})
I am working with XML files which I have successfully managed into one concatenated list and grouped as below:
["01" [{:MONTH "01", :ORDER_CATEGORY "1"} {:MONTH "01", :ORDER_CATEGORY "1"} {:MONTH "01", :ORDER_CATEGORY "2"}]] ["02" [{:MONTH "02", :ORDER_CATEGORY "1"} {:MONTH "02", :ORDER_CATEGORY "2"} {:MONTH "02", :ORDER_CATEGORY "2"}]]
Therefore, I would expect to have:
MONTH ORDER1 ORDER2
01--------2--------------1
02--------1--------------2
This may be a relatively simple fix that I'm overlooking so thanks for the help in advance!
Upvotes: 0
Views: 129
Reputation: 9276
Your for loop does not work, because you have bound a map entry like this to flop
["01" [{:MONTH "01", :ORDER_CATEGORY "1"} ...]]
And your filter expressions take that as an input:
(filter #(= "1" (:ORDER_CATEGORY %)) flop)
This will not work, because :ORDER_CATEGORY
will neither return sth. for "01"
, nor for the sequence [{:MONTH ...} ...]
.
Given that what you have bound to flop
is a MapEntry, you can use val
to fix this:
(filter #(= "1" (:ORDER_CATEGORY %)) (val flop))
.
E. g.:
(for [flop GROUPED_BY_MONTH]
{:MONTH (:MONTH (first (second flop)))
:ORDER1 (count (filter #(= "1" (:ORDER_CATEGORY %)) (val flop)))
:ORDER2 (count (filter #(= "2" (:ORDER_CATEGORY %)) (val flop)))})
=> ({:MONTH "01", :ORDER1 2, :ORDER2 1} {:MONTH "02", :ORDER1 1, :ORDER2 0})
You could also use destructoring, to make your code more clear:
(for [[month maps] GROUPED_BY_MONTH]
{:MONTH month
:ORDER1 (count (filter #(= "1" (:ORDER_CATEGORY %)) maps))
:ORDER2 (count (filter #(= "2" (:ORDER_CATEGORY %)) maps))})
=> ({:MONTH "01", :ORDER1 2, :ORDER2 1} {:MONTH "02", :ORDER1 1, :ORDER2 0})
Notice that in general, this solution is more favorable:
(reduce (fn [acc {:keys [MONTH ORDER_CATEGORY]}]
(update-in acc [MONTH ORDER_CATEGORY]
(fnil inc 0)))
{} CON)
=> {"02" {"1" 1}, "01" {"2" 1, "1" 2}}
It returns a map of month->order-category->count
that works independently of the kinds and types of order categories and months present in the input set.
E. g.
(reduce (fn [acc {:keys [MONTH ORDER_CATEGORY]}]
(update-in acc [MONTH ORDER_CATEGORY]
(fnil inc 0)))
{} (conj CON
{:MONTH "01" :ORDER_CATEGORY "foo"}
{:MONTH "02" :ORDER_CATEGORY "foo"}
{:MONTH "02" :ORDER_CATEGORY "bar"}
{:MONTH "02" :ORDER_CATEGORY "1"}))
=> {"02" {"bar" 1, "foo" 1, "1" 2}, "01" {"foo" 1, "2" 1, "1" 2}}
However you should be aware that in case of a count of 0 for an ORDER_CATEGORY
, no value is associated in the result.
Upvotes: 1
Reputation: 3951
I would first convert the data to:
user=> (pprint x)
[{:MONTH "01", :ORDER_CATEGORY "1"}
{:MONTH "01", :ORDER_CATEGORY "1"}
{:MONTH "01", :ORDER_CATEGORY "2"}
{:MONTH "02", :ORDER_CATEGORY "1"}]
and use functions:
user=> (defn inc1 [x] (if x (inc x) 1))
user=> (reduce (fn [acc {:keys [MONTH ORDER_CATEGORY]}]
(update-in acc [[MONTH ORDER_CATEGORY]] inc1)) {} x)
{["02" "1"] 1, ["01" "2"] 1, ["01" "1"] 2}
Key is [Month Category], value is the number of orders.
Upvotes: 2