I realized I could use that at some of my code so I wrote it. Not sure if
it's the best possible implementation but here it is:
(defn quantizer
"Returns a function that quantizes input data which when called with 'x'
returns: o <1st val> if -Inf < x <= <1st bound> o <2st val> if <1st
bound> < x <= <2st bound> o ... o <last val> if <last-1 bound> < x <= <last
bound> o >max if x > <last bound> where m is a vector of vectors where
the first element specifies the boundary and the second element the value
which to return. Example: (def points->grade (quantizer [[40 :F] [60 :D]
[80 :C] [90 :B]] :A)) (map points->grade [10 80 93]) ; (:F :C :A)"
[m >max]
(fn [x]
(if (<= x (first (first m)))
(second (first m))
(if (> x (first (last m)))
>max
(some
(fn [i]
(let [[[l lv] [h hv]] i]
(and (< l x) (<= x h) hv)))
(partition 2 1 m))))))
Cheers
On Sunday, February 16, 2014 6:47:51 PM UTC-5, Andy- wrote:
>
> I'm also very new to clojure but this is how I'd do it:
>
> (def hr-zones {
> [0 100] :low
> [101 120] :fat-burn
> [121 140] :aerobic
> [141 160] :anaerobic
> [161 333] :max})
>
> (defn hr->zone [hr]
> (some (fn [x]
> (and (<= (first (key x)) hr (second (key x)))
> (val x)))
> hr-zones))
>
>
> This method does have some disadvantages however (you have to make sure
> the boundaries are correct and it doesn't handle floating points like
> 140.4).
>
> Whenever you see yourself repeating code (like the 3-4 if's you have) then
> you have to take a step back and maybe change your data structure so that
> your algorithm is easier.
>
> Mathematically speaking you're really quantizing your data (aka applying a
> piecewise constant function). So you could even take another step back and
> make it more general. So find a data structure that represents the function
> (ie the intervals and the function value for each interval) and then you
> could come up with a function like "quantize" or "mk-piecewise-const-fn"
> that returns a function. So you could then do:
>
> (let [myfn (mk-piecewise-const-fn [[100 :zone-1] [120 :zone-2] ...] ]
> myzone (myfn 142)]
>
> and you have a general function which you can now use with a much wider
> range of problems (not just specific to your hr->zone conversion).
>
> But I'm too lazy to come up with a implementation for
> mk-piecewise-const-fn :)
>
> HTH
>
>
> On Sunday, February 16, 2014 5:31:46 PM UTC-5, Laurent Droin wrote:
>>
>> Hi,
>>
>> Disclaimer - I am completely new to Clojure. I just implemented my very
>> first (simple) program, letting me find out, from a GPX file, how much time
>> is spent in the various heart rate zones. Now that it's working, I'm
>> reviewing the code and trying to use best practices. From what I have read
>> so far, there are many ways in Clojure to do the same thing and for a
>> newbie, it's not always obvious to get a good grasp on what is the best way
>> to code a feature.
>> As a developer, and even though I love how concise Clojure programs can
>> be, I am very concerned with readability and ease of maintenance so I would
>> like to keep functions as short and tight as possible, but not to the point
>> where it becomes hard to understand what it does.
>>
>> Here is a function that I came up with that takes a bpm (heart beats per
>> minute) value, as well as a sequence of 4 values that represent the
>> boundaries defining the 5 different heart rate zones for a particular
>> person.
>> The function needs to finds out in what heart zone the bpm value falls
>> into and return that zone (as a keyword - I later use that keyword in a
>> map).
>>
>> If you're an experienced Clojure developer, what would you have done
>> differently (and why) ?
>>
>> *(defn hr-zone*
>> * "Return the HR zone as a keyword according to the bpm value."*
>> * [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
>> * (cond *
>> * (<= bpm max-zone-1) :hr-zone-1*
>> * (and (< max-zone-1 bpm) (>= max-zone-2 bpm)) :hr-zone-2 *
>> * (and (< max-zone-2 bpm) (>= max-zone-3 bpm)) :hr-zone-3 *
>> * (and (< max-zone-3 bpm) (>= max-zone-4 bpm)) :hr-zone-4 *
>> * (< max-zone-4 bpm) :hr-zone-5))*
>>
>> FYI, here is how I call this function in the REPL:
>> (def my-hr-zones-defs [120 150 165 180])
>>
>> (hr-zone 115 my-hr-zones-defs)
>> (hr-zone 133 my-hr-zones-defs)
>> (hr-zone 161 my-hr-zones-defs)
>> (hr-zone 175 my-hr-zones-defs)
>> (hr-zone 192 my-hr-zones-refs)
>>
>> Questions I have:
>> Would that make sense to consider (and maybe enforce) that the sequence
>> received as parameter is sorted? If this was the case, I would assume I
>> could avoid the "and" calls- assuming that all the conditions in the cone
>> form are evaluated in order.
>> Assuming that I need to test bpm against the two boundaries of each
>> range, would there be a better way to do this:
>> *(and (< max-zone-1 bpm) (>= max-zone-2 bpm))*
>> ?
>> Maybe this would work, but is it preferable?
>> *(< max-zone-1 bpm (dec **max-zone-2**))*
>>
>> *Thanks in advance for the advice.*
>>
>> *Laurent. *
>>
>>
--
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/groups/opt_out.