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, <[email protected]> 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 [email protected]
>>> Note that posts from new members are moderated - please be patient with
>>> your first post.
>>> To unsubscribe from this group, send email to
>>> [email protected]
>>> 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 [email protected].
>>> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.