17
\$\begingroup\$

Note: This is #3 in a series of challenges. For the previous challenge, click here.

Moving Average of a List

The moving average of a list is a calculation resulting in a new, smoothed out list, created by averaging small overlapping sublists of the original.

When creating a moving average, we first generate the list of overlapping sublists using a certain 'window size', shifting this window to the right once each time.

For example, given the list [8, 4, 6, 2, 2, 4] and the window size 3, the sublists would be:

[8,  4,  6,  2,  2,  4]          Sublists:
(         )                  <-  [8, 4, 6]
    (         )              <-  [4, 6, 2]
        (         )          <-  [6, 2, 2]
            (         )      <-  [2, 2, 4]

We then calculate the mean average of each sublist to obtain the result: [6.0, 4.0, 3.3, 2.7] (each value rounded to one decimal place).


The Challenge

Your task is to write a program or function which, given a list L, and an integer 1 ≤ n ≤ length(L), calculate the moving average for L using the window size n.

Rules:

  • Your program may use integer division or float division. In the case of float division, small inaccuracies due to the data type's limitations are permitted, as long as the value is otherwise correct.
  • You may submit a full program, or a function (but not a snippet).
  • You may assume that the list will only contain positive integers.
  • Standard loopholes are forbidden.
  • This is , so the shortest answer (in bytes) wins!

Test Cases

Note that, for ease of readability, all values are rounded to one decimal place.

n=5, [1, 2, 3, 4, 5, 6, 7, 8]      ->      [3, 4, 5, 6]
n=3, [100, 502, 350, 223, 195]     ->      [317.3, 358.3, 256]
n=1, [10, 10, 10]                  ->      [10, 10, 10]
n=3, [10, 20, 30]                  ->      [20]
n=2, [90, 40, 45, 100, 101]        ->      [65, 42.5, 72.5, 100.5]
\$\endgroup\$
6
  • \$\begingroup\$ Do we have to round float values, or can we leave them as they are? \$\endgroup\$ – caird coinheringaahing Nov 5 '17 at 16:01
  • 4
    \$\begingroup\$ @cairdcoinheringaahing Note that, for ease of readability, all values are rounded to one decimal place. In my opinion, you can definitely leave them as they are (at least that's what I understand). \$\endgroup\$ – Mr. Xcoder Nov 5 '17 at 16:01
  • \$\begingroup\$ @cairdcoinheringaahing I've been quite liberal with I/O: integer or float values are fine, you may round if you want but don't have to, and floating point errors are allowed \$\endgroup\$ – FlipTack Nov 5 '17 at 16:03
  • \$\begingroup\$ Is it okay to return fractions instead of floating point numbers? \$\endgroup\$ – JungHwan Min Nov 5 '17 at 16:23
  • \$\begingroup\$ @JungHwanMin If for accuracy, your language will store values as fractions rather than floats, it's fine to print them as accurate fractions in their simplest forms. \$\endgroup\$ – FlipTack Nov 5 '17 at 16:26

36 Answers 36

8
\$\begingroup\$

Dyalog APL, 4 bytes

1 byte saved thanks to @Graham

2 bytes saved thanks to @jimmy23013

Did I mention APL is not a golfing language?

⊢+/÷

with n on the right, or

+/÷⊣

with L on the right.

Try it online!

How?

÷ - divide L by n

⊢+/ - reduce + on windows of n

\$\endgroup\$
4
  • \$\begingroup\$ Why not divide L by n before the reduction. Saves a byte \$\endgroup\$ – Graham Nov 5 '17 at 16:49
  • \$\begingroup\$ ⊢+/÷ \$\endgroup\$ – jimmy23013 Nov 6 '17 at 9:13
  • \$\begingroup\$ Or +/÷⊣ \$\endgroup\$ – jimmy23013 Nov 6 '17 at 9:16
  • \$\begingroup\$ @jimmy23013 thanks alot! I tried that one earlier, but must've typed the arguments wrong cos it didn't work. \$\endgroup\$ – Uriel Nov 6 '17 at 10:51
7
\$\begingroup\$

Jelly, 3 bytes

ṡÆm

Try it online!

Pretty simple thanks to

How it works

ṡÆm - Main dyadic link. Arguments: l (list) and n (integer)
ṡ   - Split l into sublists of length n
 Æm - Mean of each
\$\endgroup\$
0
7
\$\begingroup\$

Wolfram Language (Mathematica), 13 bytes

Mathematica has a built-in for everything

MovingAverage

Try it online!

Takes a list and then a radius...

\$\endgroup\$
2
  • 6
    \$\begingroup\$ MovingAverage ಠ_____ಠ I refuse to believe this \$\endgroup\$ – Mr. Xcoder Nov 5 '17 at 16:23
  • \$\begingroup\$ @cairdcoinheringaahing Takes the numerical value. MovingAverage returns a set of fractions. Now that it's been allowed by the OP, MovingAverage should suffice indeed. \$\endgroup\$ – Mr. Xcoder Nov 5 '17 at 16:33
7
\$\begingroup\$

Haskell, 47 bytes

n!a|length a<n=[]|_:t<-a=div(sum$take n a)n:n!t

Try it online!

Saved two bytes thanks to xnor!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ tail a can be extracted in the guard. \$\endgroup\$ – xnor Nov 5 '17 at 17:30
  • \$\begingroup\$ Gah, I knew I was missing something like that. Thank you! \$\endgroup\$ – Lynn Nov 5 '17 at 20:02
6
\$\begingroup\$

Python, 48 bytes

f=lambda n,l:l[n-1:]and[sum(l[:n])/n]+f(n,l[1:])

Try it online!

A recursive function. Shorter than the program (50 bytes)

n,l=input()
while l[-n]:print sum(l[:n])/n;l=l[1:]

Try it online!

This saves 2 bytes by terminating with error on the while condition.

\$\endgroup\$
0
4
\$\begingroup\$

Enlist, 3 bytes

ṡÆm

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Polyglot with Jelly :P \$\endgroup\$ – caird coinheringaahing Nov 5 '17 at 16:38
  • \$\begingroup\$ @cairdcoinheringaahing I only just noticed your Jelly answer too lol :P \$\endgroup\$ – Mr. Xcoder Nov 5 '17 at 16:38
4
\$\begingroup\$

Perl 6, 33 bytes

{@^a.rotor($^b=>1-$b)».sum X/$b}

Test it

Expanded:

{  # bare block with placeholder parameters 「@a」, 「$b」

  @^a                # declare and use first param

  .rotor(            # split it into chunks
    $^b              # declare and use second param
    =>               # pair it with
    1 - $b           # one less than that, negated

  )».sum             # sum each of the sub lists

  X/                 # cross that using &infix:«/»

  $b                 # with the second param
}
\$\endgroup\$
4
\$\begingroup\$

C,  86   84  83 bytes

i,j,s;f(a,l,n)int*a;{for(i=-1;i+++n<l;s=!printf("%d ",s/n))for(j=n;j--;)s+=a[i+j];}

Try it online!

Unrolled:

i, j, s;
f(a, l, n)int*a;
{
    for(i=-1; i+++n<l; s=!printf("%d ", s/n))
        for(j=n; j--;)
            s += a[i+j];
}
\$\endgroup\$
0
4
\$\begingroup\$

J, 7 5 bytes

]+/\%

Try it online!

Takes n as the right argument and the list as the left. Credit to Uriel's solution for the idea of doing only the summation in the infix.

Explanation

]+/\%
    %  Divide list by n
]+/\   Sum on overlapping intervals of size n

Previous solution (7 bytes)

(+/%#)\
      \  Apply to overlapping intervals of size n
(+/%#)   Mean
 +/        Sum
   %       Divided by
    #      Length
\$\endgroup\$
4
\$\begingroup\$

Ohm v2, 3 bytes

ÇÆm

Try it online!

Explanation:

ÇÆm  Main wire, arguments l (list) and n (integer)

Ç    All consecutive sublists of l with length n
 Æm  Arithmetic mean of each sublist
\$\endgroup\$
3
\$\begingroup\$

Pyth, 5 bytes

.O.:F

Try it here!

How this works

.O.:F  - Full program.

    F  - Reduce the input (nested list) with...
  .:   - ... Sublists.
.O     - Average of each.
\$\endgroup\$
3
\$\begingroup\$

Octave, 33 31 bytes

@(x,n)conv(x,~~(1:n)/n,'valid')

Try it online!

Explanation

Convolution (conv) is essentially a moving weighted sum. If the weights are chosen as [1/n, ..., 1/n] (obtained as ~~(1:n)/n) the result is a moving average, of which only the 'valid' part is kept.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 55 bytes

lambda n,A:[sum(A[j:n+j])/n for j in range(-n-~len(A))]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

05AB1E, 5 bytes

ŒsùÅA

Explanation:

Π    All substrings
 sù   Keep those only where the length is equal to <the second input>
   ÅA Arithmetic mean of each element in the resulting array.

Try it online!

\$\endgroup\$
2
\$\begingroup\$

R, 72 bytes

function(l,n)(k=sapply(0:sum(l|1),function(x)mean(l[x+1:n])))[!is.na(k)]

Try it online!

Computes the mean of all the size n windows; when the window goes past the edge of l, the results are NA so we filter them out.

R + zoo package, 13 bytes

zoo::rollmean

The zoo package (S3 infrastructure for Regular and Irregular Time Series) has a lot of handy functions. You may try it here (R-fiddle).

\$\endgroup\$
2
\$\begingroup\$

Japt v2.0a0, 7 bytes

ãV ®x÷V

Try it


Explanation

Implicit input of array U and integer V.

ãV

Get subsections of U with length V

®

Map over the subsections.

÷V

Divide each element by V.

x

Sum all elements.

\$\endgroup\$
2
\$\begingroup\$

Factor + math.extras, 14 bytes

moving-average

Try it online!

Built-in.


Factor, 22 bytes

[ clump [ mean ] map ]

Try it online!

Explanation:

A non-trivial answer. It's a quotation (anonymous function) that takes a sequence and an integer from the data stack as input and leaves a sequence on the data stack as output.

  • clump Split a sequence into groups of n with overlapping. This creates the moving window.
  • [ mean ] map Map each window to its mean.
\$\endgroup\$
1
\$\begingroup\$

Python 3, 61 bytes

lambda l,n:[sum(e)/n for e in zip(*[l[i:]for i in range(n)])]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Mathematica, 21 bytes

Mean/@##~Partition~1&

Try it online!

-3 bytes JungHwan Min

\$\endgroup\$
1
  • \$\begingroup\$ -3 bytes: N[Mean/@##~Partition~1]& \$\endgroup\$ – JungHwan Min Nov 5 '17 at 16:24
1
\$\begingroup\$

Proton, 46 bytes

n=>l=>[sum(l[h to h+n])/n for h:0..len(l)-n+1]

Try it online!

Note that this takes input via currying functions syntax, and returns a list of fractions.

\$\endgroup\$
1
\$\begingroup\$

Jq 1.5, 61 bytes

def f(N;L):[L|range(0;1+length-N)as$i|.[$i:$i+N]|add/length];

Expanded

def f(N;L):
  [   L
    | range(0;1+length-N) as $i        # generate
    | .[$i:$i+N]                       # sublists
    | add/length                       # compute mean
  ];

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Make only N a parameter, and take L from the stream: 57 bytes JqPlay (I know I'm years late, but couldn't resist) \$\endgroup\$ – Wezl Apr 28 at 15:50
1
\$\begingroup\$

CJam, 14 12 bytes

-2 bytes thanks to @aditsu

{_@ew::+\f/}
\$\endgroup\$
0
1
\$\begingroup\$

x86 Machine Code, 20 bytes

86 89 D9 31 C0 03 44 8F FC E2 FA 31 D2 F7 F3 AB 39 F7 72 ED C3

The above bytes define a function that calculates the moving average of a list, modifying the elements of the list in-place. It assumes that the list is a contiguous array of integer elements. The function takes the following inputs in registers

  • edi: the address of the first element in the list (i.e., a pointer to the beginning of the array)
  • esi: the address of the element following the last element in the list (i.e., a pointer to one past the end of the array)
  • ebx: the size of the window (i.e., number of elements to consider in each window)

This is a custom calling convention, which is common when writing machine/assembly language functions. All averaging operations are done internally in integer mode, as provided for by the challenge.

The input array, bounded by the addresses specified as edi and esi, is modified in-place by the function: the first n elements are replaced with the corresponding moving average. Thus, the caller just discards all but the first n elements.

Try it online!

Here are the ungolfed assembly mnemonics:

MovingAverage:
; Inputs:
;    edi = &array[0]
;    esi = &array[N]
;    ebx = cWindow
; Outputs:
;    array is modified in-place, starting from the beginning
; Clobbers:
;    eax, ecx, edx, edi, flags
              OuterLoop:
89 D9            mov    ecx, ebx
31 C0            xor    eax, eax
              InnerLoop:
03 44 8F FC      add    eax, DWORD PTR [edi + ecx * 4 - 4]
E2 FA            loop   InnerLoop
31 D2            xor    edx, edx
F7 F3            div    ebx
AB               stos ; DWORD PTR [edi], eax; sub edi, 4
39 F7            cmp    edi, esi
72 ED            jb     OuterLoop
C3               ret

The assembly code should be pretty self-explanatory, although I hope sufficiently clever! The code basically just runs two loops. The outer loop iterates through the entire array, one element at a time. The inner loop starts at the current element, iterates through the length of the window, and computes the sum. After the inner loop, the sum is used to compute the average (simple division by the window size), and then the resulting moving average for that "sublist" is written back into the original array at the current index.

Very few notable "tricks" here. Of mention:

  • Cleverly choosing the calling convention allows significant savings with the elision of unnecessary MOV instructions. (Of course, that burden is transferred onto the caller, but they're not playing code golf!)
  • The string instruction, STOSD, is used to save a large number of bytes; encoded with only 1 byte, it writes the contents of the eax register back to the memory location contained in edi, while simultaneously incrementing edi by 4 bytes to contain the location of the next element.
  • The LOOP instruction (which does a combined decrement of ecx and loop if its new value is not equal to 0) is used to save a couple of bytes.
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 53 bytes

(l,n)=>l.map(e=>(s+=e-=a[i-n]||0)/n,s=i=0).slice(n-1)
\$\endgroup\$
0
\$\begingroup\$

PHP, 94 bytes

function f($l,$n){while($i<=count($l)-$n)$r[]=array_sum(array_slice($l,$i++,$n))/$n;return$r;}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Clojure, 48 bytes

(fn[n a](map #(/(apply + %)n)(partition n 1 a)))

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Stacked, 22 bytes

[infixes[:sum\#'/]map]

Try it online!

Explanation

infixes generates all the windows of the given length. Then, we map our own average function over each infix.

\$\endgroup\$
0
\$\begingroup\$

Common Lisp, 77 bytes

(defun f(x y)(if(>=(length x)y)(cons(/(apply'+(subseq x 0 y))y)(f(cdr x)y))))

Try it online!

\$\endgroup\$
0
\$\begingroup\$

K (oK), 13 11 bytes

Solution:

{+/+x':y%x}

Try it online!

Examples:

{+/+x':y%x}[3;8 4 6 2 2 4]
6 4 3.3333 2.6667
{+/+x':y%x}[5;1 2 3 4 5 6 7 8]
3 4 5 6

Explanation:

oK has a built-in for creating a sliding window, then sum up resulting arrays and divide by sliding window size to get mean:

{+/+x':y%x} / the solution
{         } / lambda function taking x and y as implicit parameters
       y%x  / y (list) by x (sliding array size)
    x':     / sliding window of size x over list y
   +        / flip array (rotate by 90 degrees)
 +/         / sum up array
\$\endgroup\$
2
  • \$\begingroup\$ Looks like you don't need the flip array +, and if K has commute like APL you can move x%[commute] to left and drop the parens \$\endgroup\$ – Uriel Nov 6 '17 at 15:10
  • \$\begingroup\$ The flip is needed to ensure the sum is across rather than down each list, and fairly sure there's no commute operator, at least nothing to suggest it in the manual. Cheers though! \$\endgroup\$ – streetster Nov 6 '17 at 16:23
0
\$\begingroup\$

DataWeave, 50 bytes

fun s(l,w)=0 to(sizeOf(l)-w)map avg(l[$ to $+w-1])
%dw 2.0
output application/json

fun sma(list: Array<Number>, window: Number) =
  0 to (sizeOf(list) - window)  // generate starting indices of sublists
  map list[$ to $ + window - 1] // generate sublists
  map avg($)                    // calculate averages

---
sma([90, 40, 45, 100, 101], 2)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.