Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I know Clojure better than Scala, so here goes. As I write this the other Clojure entry here is imperative; that's not really what you're after (and isn't idiomatic Clojure). The first algorithm that comes to my mind is repeatedly taking the requested number of elements from the sequence, dropping the first element, and recurring. </p> <p>The following works on any kind of sequence (vector or list, lazy or not) and gives a lazy sequence of averages---which could be helpful if you're working on a list of indefinite size. Note that it takes care of the base case by implicitly returning nil if there aren't enough elements in the list to consume.</p> <pre><code>(defn moving-average [values period] (let [first (take period values)] (if (= (count first) period) (lazy-seq (cons (/ (reduce + first) period) (moving-average (rest values) period)))))) </code></pre> <p>Running this on your test data yields</p> <pre><code>user&gt; (moving-average '(2.0, 4.0, 7.0, 6.0, 3.0, 8.0, 12.0, 9.0, 4.0, 1.0) 4) (4.75 5.0 6.0 7.25 8.0 8.25 6.5) </code></pre> <p>It doesn't give "0" for the first few elements in the sequence, though that could easily be handled (somewhat artificially). </p> <p>The easiest thing of all is to see the pattern and be able to bring to mind an available function that fits the bill. <code>partition</code> gives a lazy view of portions of a sequence, which we can then map over:</p> <pre><code>(defn moving-average [values period] (map #(/ (reduce + %) period) (partition period 1 values)) </code></pre> <p>Someone asked for a tail recursive version; tail recursion vs. laziness is a bit of a tradeoff. When your job is building up a list then making your function tail recursive is usually pretty simple, and this is no exception---just build up the list as an argument to a subfunction. We'll accumulate to a vector instead of a list because otherwise the list will be built up backwards and will need to be reversed at the end.</p> <pre><code>(defn moving-average [values period] (loop [values values, period period, acc []] (let [first (take period values)] (if (= (count first) period) (recur (rest values) period (conj acc (/ (reduce + first) period))) acc)))) </code></pre> <p><code>loop</code> is a way to make an anonymous inner function (sort of like Scheme's named let); <code>recur</code> must be used in Clojure to eliminate tail calls. <code>conj</code> is a generalized <code>cons</code>, appending in the manner natural for the collection---the beginning of lists and the end of vectors.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload