An Array of Challenges #3: Moving Averages

16

2

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]

FlipTack

Posted 2017-11-05T15:46:25.740

Reputation: 13 242

Do we have to round float values, or can we leave them as they are? – caird coinheringaahing – 2017-11-05T16:01:05.887

3@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). – Mr. Xcoder – 2017-11-05T16:01:29.623

@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 – FlipTack – 2017-11-05T16:03:36.360

Is it okay to return fractions instead of floating point numbers? – JungHwan Min – 2017-11-05T16:23:05.440

@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. – FlipTack – 2017-11-05T16:26:41.353

Related (sliding window on a string) – FlipTack – 2017-12-27T18:17:34.400

Answers

7

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

caird coinheringaahing

Posted 2017-11-05T15:46:25.740

Reputation: 13 702

7

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

Uriel

Posted 2017-11-05T15:46:25.740

Reputation: 11 708

Why not divide L by n before the reduction. Saves a byte – Graham – 2017-11-05T16:49:57.433

⊢+/÷ – jimmy23013 – 2017-11-06T09:13:15.250

Or +/÷⊣

– jimmy23013 – 2017-11-06T09:16:30.003

@jimmy23013 thanks alot! I tried that one earlier, but must've typed the arguments wrong cos it didn't work. – Uriel – 2017-11-06T10:51:37.263

7

Wolfram Language (Mathematica), 13 bytes

Mathematica has a built-in for everything

MovingAverage

Try it online!

Takes a list and then a radius...

JungHwan Min

Posted 2017-11-05T15:46:25.740

Reputation: 13 290

6MovingAverage ಠ_____ಠ I refuse to believe this – Mr. Xcoder – 2017-11-05T16:23:18.977

@cairdcoinheringaahing Takes the numerical value. MovingAverage returns a set of fractions. Now that it's been allowed by the OP, MovingAverage should suffice indeed. – Mr. Xcoder – 2017-11-05T16:33:07.717

7

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!

Lynn

Posted 2017-11-05T15:46:25.740

Reputation: 55 648

1tail a can be extracted in the guard. – xnor – 2017-11-05T17:30:02.683

Gah, I knew I was missing something like that. Thank you! – Lynn – 2017-11-05T20:02:04.720

6

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.

xnor

Posted 2017-11-05T15:46:25.740

Reputation: 115 687

4

Enlist, 3 bytes

ṡÆm

Try it online!

Mr. Xcoder

Posted 2017-11-05T15:46:25.740

Reputation: 39 774

Polyglot with Jelly :P – caird coinheringaahing – 2017-11-05T16:38:19.743

@cairdcoinheringaahing I only just noticed your Jelly answer too lol :P – Mr. Xcoder – 2017-11-05T16:38:40.217

4

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
}

Brad Gilbert b2gills

Posted 2017-11-05T15:46:25.740

Reputation: 12 713

4

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];
}

Steadybox

Posted 2017-11-05T15:46:25.740

Reputation: 15 798

4

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

Nick Clifford

Posted 2017-11-05T15:46:25.740

Reputation: 1 184

4

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

cole

Posted 2017-11-05T15:46:25.740

Reputation: 3 526

3

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.

Mr. Xcoder

Posted 2017-11-05T15:46:25.740

Reputation: 39 774

3

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.

Luis Mendo

Posted 2017-11-05T15:46:25.740

Reputation: 87 464

2

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.

Shaggy

Posted 2017-11-05T15:46:25.740

Reputation: 24 623

2

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).

Giuseppe

Posted 2017-11-05T15:46:25.740

Reputation: 21 077

1

Python 3, 61 bytes

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

Try it online!

notjagan

Posted 2017-11-05T15:46:25.740

Reputation: 4 011

1

Python 3, 55 bytes

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

Try it online!

Jonathan Frech

Posted 2017-11-05T15:46:25.740

Reputation: 6 681

1

Mathematica, 21 bytes

Mean/@##~Partition~1&

Try it online!

-3 bytes JungHwan Min

J42161217

Posted 2017-11-05T15:46:25.740

Reputation: 15 931

-3 bytes: N[Mean/@##~Partition~1]& – JungHwan Min – 2017-11-05T16:24:08.800

1

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!

Okx

Posted 2017-11-05T15:46:25.740

Reputation: 15 025

1

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.

Mr. Xcoder

Posted 2017-11-05T15:46:25.740

Reputation: 39 774

1

CJam, 14 12 bytes

-2 bytes thanks to @aditsu

{_@ew::+\f/}

Esolanging Fruit

Posted 2017-11-05T15:46:25.740

Reputation: 13 542

0

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!

jq170727

Posted 2017-11-05T15:46:25.740

Reputation: 411

0

JavaScript (ES6), 53 bytes

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

Neil

Posted 2017-11-05T15:46:25.740

Reputation: 95 035

0

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!

Jo.

Posted 2017-11-05T15:46:25.740

Reputation: 974

0

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

streetster

Posted 2017-11-05T15:46:25.740

Reputation: 3 635

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 – Uriel – 2017-11-06T15:10:23.620

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!

– streetster – 2017-11-06T16:23:55.200

0

Clojure, 48 bytes

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

Try it online!

MattPutnam

Posted 2017-11-05T15:46:25.740

Reputation: 521

0

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)

menduz

Posted 2017-11-05T15:46:25.740

Reputation: 1

0

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.

Conor O'Brien

Posted 2017-11-05T15:46:25.740

Reputation: 36 228

0

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!

ceilingcat

Posted 2017-11-05T15:46:25.740

Reputation: 5 503

0

Funky, 67 66 bytes

Saved a byte with curry syntax.

n=>t=>{k={}fori=0i<=(#t)-n i++k[i]=(forj=c=0c<n c++j+=t[i+c])/n k}

Try it online!

ATaco

Posted 2017-11-05T15:46:25.740

Reputation: 7 898

0

Java 8, 111 bytes

a->n->{int l=a.length-n+1,i=0,j;float[]r=new float[l];for(;i<l;r[i++]/=n)for(j=i;j<i+n;r[i]+=a[j++]);return r;}

Explanation:

Try it here.

a->n->{                 // Method with array and int parameters and float-array return-type
  int l=a.length-n+1,   //  New length of the return-array
      i=0,j;            //  Index-integers
  float[]r=new float[l];//  Return-array
  for(;i<l;             //  Loop (1) from 0 to `l` (exclusive)
      r[i++]/=n)        //    After every iteration, divide the current item by input `n`
    for(j=i;j<i+n;      //   Inner loop (2) from `i` to `i+n` (exclusive)
      r[i]+=a[j++]      //    Sum the result at index `i` with the items of the input-array
    );                  //   End of inner loop (2)
                        //  End of loop (1) (implicit / single-line body)
  return r;             //  Return the resulting float-array
}                       // End of method

Kevin Cruijssen

Posted 2017-11-05T15:46:25.740

Reputation: 67 575

0

Ruby, 35 bytes

->l,n{l.each_cons(n){|x|p x.sum/n}}

Try it online!

G B

Posted 2017-11-05T15:46:25.740

Reputation: 11 099

0

Python 57 bytes:

lambda L,n:[sum(L[i:(i+n)])/n for i in range(len(L)-n+1)]

rnso

Posted 2017-11-05T15:46:25.740

Reputation: 1 635