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.