Thank you all. I especially like the use of reduce-kv and the 2 fnils. I 
looked at reduce-kv, but I was too stupid to figure out how to apply it 
here. 


On Tuesday, May 26, 2015 at 12:27:16 PM UTC-4, Francis Avila wrote:
>
> Your two functions can be written more succinctly (and with fewer explicit 
> conditionals) like these, but they will be harder for a beginner to 
> understand. (The nested update-in with fnil in particular may cause 
> confusion.)
>
>
> (defn add-placeholder-to-history [users]
>   (reduce-kv (fn [users uk {:keys [history]}]
>                (assoc-in users [uk :history]
>                  (into [{}] (take 2 history))))
>     users users))
>
>
> (defn update-history [users {:keys [category prize-money winner]}]
>   (update-in users [winner]
>     (fnil update-in {:history [{}]}) [:history 0 category]
>     (fnil + 0) prize-money))
>
>
> You may have a good pedagogical reason for your current implementation, 
> but I would take a different approach: build the new history entries first, 
> then add them to the users.
>
>
> (defn winnings-by-user [contests]
>   (reduce
>     (fn [user+winning {:keys [category winner prize-money]}]
>       (update-in user+winning [winner category] (fnil + 0) prize-money))
>     {} contests))
>
> (defn update-histories [users new-winnings]
>   (let [all-user-keys (set (concat (keys users) (keys new-winnings)))]
>     (reduce (fn [users ukey]
>               (update-in users [ukey :history]
>                 #(into [(get new-winnings ukey {})] (take 2 %))))
>       users all-user-keys)))
>
>
> (update-histories users (winnings-by-user contests))
>
>
>
>
>
>
>
> On Tuesday, May 26, 2015 at 12:37:34 AM UTC-5, Chris Freeman wrote:
>>
>> It seems like, if you don't mind doing the assoc all the time, you could 
>> replace the whole if with something like:
>>
>> (assoc nu (:winner c) (or ((:winner c) nu) {:history [{}]}))
>>
>> You might want to wrap that in a let so you don't repeat (:winner c). 
>>
>> Also, it looks like add-placeholder-to-history could be a map over an 
>> update-in instead of a loop, like:
>>
>> (defn prepend-hash [x]
>>   (into [{}] x))
>>
>> (defn add-placeholder-to-history [us]
>>   (into {} (map #(update-in % [1 :history] prepend-hash) us)))
>>
>> Chris
>>
>>
>>
>> On Mon, May 25, 2015 at 5:07 PM, <lawr...@waleup.com> wrote:
>>
>>>
>>> I started to write an essay, aimed at those programmers who are 
>>> experienced with highly mutable languages such as Javascript, Ruby, PHP, 
>>> etc, to demonstrate how one's code style changes when one switches to a 
>>> mostly immutable language such as Clojure. However, my Clojure code is not 
>>> nearly as terse as I wanted. In particular, I have this nil check: 
>>>
>>>       (if (nil? ((:winner c) nu))
>>>           (assoc nu (:winner c) {:history [{}]})
>>>         nu) 
>>>
>>> which I assume I am writing because I am ignorant. I'm guessing there 
>>> might be something clever I can do to avoid this? 
>>>
>>> For my code examples, I'm working with these 2 data structures: 
>>>
>>> (def users  {
>>>              :henry {
>>>                :history 
>>>                [
>>>                  {:housing  25, :restaurants 40, :theater 930},
>>>                  {:restaurants  30, :crisis  220}
>>>                ]
>>>               },
>>>               :lisa  {
>>>                :history 
>>>                [
>>>                  {:theater  80},
>>>                  {:housing  445, :restaurants  15, :theater  35}
>>>                ]
>>>               },
>>>               :pasha  {
>>>                :history 
>>>                [
>>>                  {:restaurants  5},
>>>                  {:restaurants  40, :theater  60}
>>>                ]
>>>               },
>>>               :eli  {
>>>                :history 
>>>                [
>>>                  {:crisis  135, :restaurants  440, :theater  65},
>>>                  {:theater  95}
>>>                ]
>>>               }
>>>             })
>>>
>>> (def contests [{:category :housing, :prize-money 100, :winner :eli},
>>>                {:category :housing, :prize-money 30, :winner :henry},
>>>                {:category :housing, :prize-money 340, :winner :henry},
>>>                {:category :housing, :prize-money 45, :winner :susan},
>>>                {:category :housing, :prize-money 15, :winner :henry},
>>>                {:category :housing, :prize-money 10, :winner :pasha},
>>>                {:category :housing, :prize-money 25, :winner :pasha},
>>>                {:category :crisis, :prize-money 100, :winner :eli},
>>>                {:category :crisis, :prize-money 2330, :winner :henry},
>>>                {:category :crisis, :prize-money 90, :winner :henry},
>>>                {:category :restaurants, :prize-money 1130, :winner :eli},
>>>                {:category :restaurants, :prize-money 130, :winner 
>>> :pasha},
>>>                {:category :theater, :prize-money 60, :winner :eli},
>>>                {:category :theater, :prize-money 90, :winner :pasha},
>>>                {:category :theater, :prize-money 130, :winner :pasha},
>>>                {:category :theater, :prize-money 830, :winner :susan},
>>>                {:category :theater, :prize-money 90, :winner :susan},
>>>                {:category :theater, :prize-money 270, :winner :eli}])
>>>
>>> Presumably "users" shows past winnings from 2 rounds of some contest, 
>>> whereas "contests" shows the winnings from the 3rd round, which need to be 
>>> added to "users". So I wrote: 
>>>
>>>
>>> (defn add-placeholder-to-history [us]
>>>       (loop [u us nu {}] 
>>>         (if (first u) 
>>>           (recur
>>>             (rest u)
>>>             (assoc nu (get (first u) 0) {:history (into [] (cons {} 
>>> (:history (get (first u) 1))))}))
>>>           nu)))
>>>           
>>> (defn update-history [nu c]          
>>>     (update-in 
>>>       (if (nil? ((:winner c) nu))
>>>           (assoc nu (:winner c) {:history [{}]})
>>>         nu) 
>>>       [(:winner c) :history 0 (:category c)] (fnil #(+ %1 (:prize-money 
>>> c)) 0)))
>>>
>>> And so in the end we would simply call: 
>>>
>>> (reduce
>>>   update-history
>>>   (add-placeholder-to-history users)
>>>   contests)
>>>
>>> Which correctly gives me: 
>>>
>>> {
>>> :susan {
>>>   :history [{:theater 920, :housing 45}]
>>>   }
>>> :lisa {
>>>   :history [{} 
>>>             {:theater 80}
>>>             {:housing 445, :restaurants 15, :theater 35}]
>>>   }
>>> :henry {
>>>   :history [{:crisis 2420, :housing 385}
>>>             {:housing 25, :restaurants 40, :theater 930}
>>>             {:crisis 220, :restaurants 30}]
>>>   }
>>> :eli {
>>>   :history [{:theater 330, :restaurants 1130, :crisis 100, :housing 100}
>>>             {:crisis 135, :restaurants 440, :theater 65}
>>>             {:theater 95}]
>>>   }
>>> :pasha {
>>>   :history [{:theater 220, :restaurants 130, :housing 35}
>>>             {:restaurants 5}
>>>             {:restaurants 40, :theater 60}]
>>>   }
>>> }
>>>
>>> And then I wrote: 
>>>
>>> -----------------------------------
>>>
>>> By the way, you might be wondering what this is for: 
>>>
>>>       (if (nil? ((:winner c) nu))
>>>           (assoc nu (:winner c) {:history [{}]})
>>>         nu) 
>>>
>>> We do this for Susan. She is a new contestant who won some money in the 
>>> newest round of contests, however, she does not yet exist in "users", so we 
>>> need to create a space for her. Without these 3 lines of code, we get this 
>>> for her: 
>>>
>>> {:susan {:history {0 {:theater 920, :housing 45}}},
>>>
>>> But with these 3 lines of code, we get the correct results for her, and 
>>> for everyone else.
>>>
>>> -----------------------------------
>>>
>>> I am wondering if I can avoid those 3 lines of code? 
>>>
>>>
>>>
>>>
>>>  -- 
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To post to this group, send email to clo...@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+u...@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 unsubscribe from this group and stop receiving emails from it, send 
>>> an email to clojure+u...@googlegroups.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to