11
\$\begingroup\$

Let's say that this array is how many press-ups I've achieved each day in the last 28 days:

[
  20,20,20,30,30,30,30,
  35,35,40,40,40,45,45,
  50,50,50,50,50,50,50,
  60,70,80,90,100,110,120
]

As you can see, it's taken a steep upward trend in the last week, and that's the part of this data I'm most interested in. The further in the past it is, the less I want that data to feature in my 'average' number of press-ups.

To that end, I want to work out an 'average' where each week is worth more than the previous week.


Background information, not part of this problem.

Normal average:

The sum of all values / the number of values

For above:

1440 / 28 = 51.42857142857143


Weighted average:

Split the array into 4 groups of 7, and start up a new array.

  • Add the first group to the array.
  • Add the second group to the array twice.
  • Add the third group to the array thrice.
  • Add the fourth group to the array four times.

Sum all of the new array, and divide by the length of the new array.

For above:

Convert the array to this:

[
  20,20,20,30,30,30,30, # first week once
  35,35,40,40,40,45,45, 
  35,35,40,40,40,45,45, # second week twice
  50,50,50,50,50,50,50,
  50,50,50,50,50,50,50,
  50,50,50,50,50,50,50, # third week thrice
  60,70,80,90,100,110,120,
  60,70,80,90,100,110,120,
  60,70,80,90,100,110,120,
  60,70,80,90,100,110,120 # Fourth week four times
]

Then run a normal average on that array.

4310 / 70 = 61.57142857142857

Note that it's higher than the normal average value because of the upward trend in the last week.


The rules:

  • The input is a flat array of 28 nonnegative integers.
  • Any language you'd like to write in.
  • Output a number.
  • I always like to see TIO links.
  • Try to solve the problem in the smallest number of bytes.
  • The result should be a decimal accurate to at least 4 decimal places (either truncated or rounded up from the test case values is fine) or an exact fraction.

Test cases:

Case 1: Upward trend

[
  20,20,20,30,30,30,30,
  35,35,40,40,40,45,45,
  50,50,50,50,50,50,50,
  60,70,80,90,100,110,120
]

Normal average: 51.42857142857143 Weighted average: 61.57142857142857

Case 2: Leaving the lull behind

(I had a bad week, but it was a while ago)

[
  50,50,50,50,50,50,50,
  10,10,10,10,10,10,10,
  50,50,50,50,50,50,50,
  50,50,50,50,50,50,50
]

Normal average: 40 Weighted average: 42

Case 3: Giving up

I had a bad week, it's pulling my average down fast.

[
  50,50,50,50,50,50,50,
  50,50,50,50,50,50,50,
  50,50,50,50,50,50,50,
  10,10,10,10,10,10,10
]

Normal average: 40 Weighted average: 34

Case 4: Averaging out

Okay, so I'm just playing around here, I thought it might be the same value for the normal and weighted averages, but, of course, it was not.

[
  60,60,60,60,60,60,60,
  30,30,30,30,30,30,30,
  20,20,20,20,20,20,20,
  15,15,15,15,15,15,15
]

Normal average: 31.25 Weighted average: 24.0


Bonus problem:

What combination of 28 values would have the same normal average and weighted average?


Happy golfing!

\$\endgroup\$
6
  • \$\begingroup\$ Let us continue this discussion in chat. \$\endgroup\$
    – AJFaraday
    May 2, 2018 at 16:55
  • 1
    \$\begingroup\$ You might want to try exponential smoothing too - new_avg = α*weekly_sum + (1-α)*old_avg for some α∈(0,1) \$\endgroup\$
    – Angs
    May 2, 2018 at 17:16
  • 2
    \$\begingroup\$ I do 0 press-ups every day, so my weighted average is the same as my normal average. \$\endgroup\$
    – Neil
    May 2, 2018 at 20:40
  • \$\begingroup\$ @Neil you would not benefit from the weighted average system ;) \$\endgroup\$
    – AJFaraday
    May 2, 2018 at 20:41
  • 1
    \$\begingroup\$ be careful not to overtrain :p \$\endgroup\$
    – Brian H.
    May 3, 2018 at 8:36

28 Answers 28

10
\$\begingroup\$

Python 3, 38 bytes

lambda x:sum(x+x[7:]+x[14:]+x[21:])/70

Try it online!

\$\endgroup\$
5
\$\begingroup\$

05AB1E, 8 7 bytes

Saved 1 byte thanks to Mr. Xcoder

7ô.s˜ÅA

Try it online!

Explanation

7ô         # split list into groups of 7
  .s       # push suffixes
    ˜      # flatten
     ÅA    # arithmetic mean
\$\endgroup\$
1
  • \$\begingroup\$ @Mr.Xcoder: Oh yeah, I knew I had seen a mean function, but I couldn't find it :P \$\endgroup\$
    – Emigna
    May 2, 2018 at 17:06
4
\$\begingroup\$

Jelly, 7 bytes

s7ṫJFÆm

Try it online!

How it works

s7ṫJFÆm  Main link. Argument: A (array of length 28)

s7       Split the array into chunks of length 7.
   J     Indices; yield [1, ..., 28].
  ṫ      Tail; yield the 1st, ..., 28th suffix of the result to the left.
         Starting with the 5th, the suffixes are empty arrays.
    F    Flatten the resulting 2D array.
     Æm  Take the arithmetic mean.
\$\endgroup\$
2
  • \$\begingroup\$ Huh, so x"J$ is equivalent to ṫJ in this context. Interesting! \$\endgroup\$
    – Mr. Xcoder
    May 2, 2018 at 16:58
  • \$\begingroup\$ Sort of. Instead of repeating the elements of the n-th array n times, this takes all suffixes. After flattening, it generates the same elements, but in a different order. \$\endgroup\$
    – Dennis
    May 2, 2018 at 17:00
4
\$\begingroup\$

R+pryr, 32 28 bytes

and the same average score week over week would result in equality of the means.

pryr::f(s%*%rep(1:4,e=7)/70)

Try it online!

Saved 4 bytes by using dot product thanks to Giuseppe.

Pure R would have two more bytes using function

\$\endgroup\$
4
  • \$\begingroup\$ Of course it would, that's so obvious, now I think about it. \$\endgroup\$
    – AJFaraday
    May 2, 2018 at 16:54
  • 1
    \$\begingroup\$ 28 bytes using dot product instead of sum \$\endgroup\$
    – Giuseppe
    May 2, 2018 at 16:58
  • \$\begingroup\$ I had 40 bytes with function(s)weighted.mean(s,rep(1:4,e=7)) \$\endgroup\$
    – Giuseppe
    May 2, 2018 at 16:58
  • 1
    \$\begingroup\$ @Giuseppe Luckily I did not remember weighted.mean. Love it when R outgolfs Python. \$\endgroup\$
    – JayCe
    May 2, 2018 at 17:27
4
\$\begingroup\$

MATL, 10 bytes

7es4:*s70/

Try it online!

I haven't posted a MATL answer in ages! Figured I might participate as part of LOTM May 2018!

Explanation:

7e          % Reshape the array into 7 rows (each week is one column)
  s         % Sum each column
   4:       % Push [1 2 3 4]
     *      % Multiply each columnar sum by the corresponding element in [1 2 3 4]
      s     % Sum this array
       70/  % Divide by 70
\$\endgroup\$
1
  • \$\begingroup\$ I had K:7Y"*s70/ at 10 bytes as well. \$\endgroup\$
    – Giuseppe
    May 4, 2018 at 22:20
3
\$\begingroup\$

Husk, 6 bytes

AΣΣṫC7

Try it online!

Uses the trick Dennis used to outgolf my Jelly submission. Instead of repeating each chunk N times, it retrieves the suffixes of the list of chunks, which after flattening will yield the same result, except for the order.

\$\endgroup\$
3
\$\begingroup\$

Jelly, 9 bytes

s7x"J$FÆm

Try it online!

How it works

s7x"J$FÆm – Takes input from the first command line argument and outputs to STDOUT.
s7        – Split into groups of 7.
   "      – Apply vectorised (zipwith):
  x J$    – Repeat the elements of each list a number of times equal to the list's index.
      F   – Flatten.
       Æm – Arithmetic mean.
\$\endgroup\$
2
\$\begingroup\$

Haskell, 35 bytes

(/70).sum.zipWith(*)([1..]<*[1..7])

Bonus: if a,b,c,d are the weekly sums, normal average is the same as weighted average iff:

(a + b + c + d)/4 = (a + 2b + 3c + 4d)/10  <=>
10(a + b + c + d) = 4(a + 2b + 3c + 4d)    <=>
5(a + b + c + d)  = 2(a + 2b + 3c + 4d)    <=>
5a + 5b + 5c + 5d = 2a + 4b + 6c + 8d      <=>
3a + b - c - 3d   = 0

One solution is when first and last week have same sums, and likewise second and third weeks have the same sum, but there are infinitely many solutions if your biceps are up to it. Example: [15,10,10,10,10,10,5,20,20,20,25,25,20,20,30,20,20,20,20,20,20,10,10,20,0,10,10,10]

Try it online!

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

JavaScript (Node.js), 49 bytes

a=>a.map((x,i)=>(I+=d=-~(i/7),s+=x*d),s=I=0)&&s/I

Try it online!


Non generics solution

JavaScript (Node.js), 39 36 bytes

a=>a.reduce((s,x,i)=>s+x*-~(i/7))/70

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ -1 byte on the first solution using a=>a.reduce((s,x,i)=>(I+=d=-~(i/7),s+x*d),I=0)/I. And a quick tip: use <hr> to create a horizontal line in markdown \$\endgroup\$
    – Endenite
    May 2, 2018 at 17:06
  • \$\begingroup\$ @HermanL What's wrong with using --- (needs its own paragraph)? \$\endgroup\$
    – Neil
    May 2, 2018 at 20:30
2
\$\begingroup\$

Stax, 6 bytes

ñI"%"╟

Run and debug it at staxlang.xyz!

Unpacked (7 bytes) and explanation:

7/|]$:V
7/         Split into groups of seven.
  |]       Suffixes
    $:V    Flatten and average. Implicit print as fraction.
\$\endgroup\$
2
\$\begingroup\$

Stax, 10 8 bytes

äΔ6◙█µøΓ

Run and debug it

Explanation (unpacked):

7/4R:B$:V Full program, implicit input
7/        Split into parts of length 7
  4R      Push [1, 2, 3, 4]
    :B    Repeat each element the corresponding number of times
      $   Flatten
       :V Average
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Another using Stax! Yes! You can use $ to flatten if the elements are all integers—checking with OP now. \$\endgroup\$ May 2, 2018 at 17:33
2
\$\begingroup\$

Octave, 33 bytes

@(x)sum(reshape(x,7,4)*(1:4)')/70

Try it online!

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

Charcoal, 14 bytes

I∕ΣE⪪A⁷×Σι⊕κ⁷⁰

Try it online! Link is to verbose version of code. Explanation:

     A          Input array
    ⪪ ⁷         Split into subarrays of length 7
   E            Loop over each subarray
         ι      Subarray
        Σ       Sum
           κ    Loop index
          ⊕     Incremented
       ×        Product
  Σ             Sum results
            ⁷⁰  Literal 70
 ∕              Divide
I               Cast to string
                Implicitly print
\$\endgroup\$
2
\$\begingroup\$

K4 / K (oK), 19 16 14 bytes

Solution:

+/(1+&4#7)%70%

Try it online!

Example:

+/(1+&4#7)%70%50 50 50 50 50 50 50 10 10 10 10 10 10 10 50 50 50 50 50 50 50 50 50 50 50 50 50 50
42

Explanation:

Evaluation is perform right-to-left. Divide 7 1s, 7 2s, 7 3s and 7 4s by 70 divided by the input; then sum up.

+/(1+&4#7)%70% / the solution               
           70% / 70 divided by the input
  (      )%    / the stuff in brackets divided by this...
      4#7      / draw from 7, 4 times => 7 7 7 7
     &         / 'where' builds 7 0s, 7 1s, 7 2s, 7 3s
   1+          / add one
+/             / sum (+) over (/) to get the total
\$\endgroup\$
2
\$\begingroup\$

Excel: 33 bytes

(3 bytes saved from @wernisch's answer by running data on 2 lines from A1:N1 and A2:N2)

=AVERAGE(A1:N2,H1:N2,A2:N2,H2:N2)

Apologies for not including this as a comment. I don't have enough reputation to do so.

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

Japt, 11 10 bytes

xÈ/#F*ÒYz7

Try it


Explanation

 È             :Pass each element at index Y through a function
  /#F          :  Divide by 70
       Yz7     :  Floor divide Y by 7
      Ò        :  Negate the bitwise NOT of that to add 1
     *         :  Multiply both results
x               :Reduce by addition
\$\endgroup\$
2
\$\begingroup\$

Arturo, 40 bytes

$[a][i:0(sum map a'x[x*1+i/7i:i+1])//70]

Try it

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

Triangularity, 49 bytes

....)....
...D7)...
..14)21..
.WM)IEtu.
}u)70s/..

Try it online!

Explanation

)D7)14)21WM)IEtu}u)70s/ – Full program.
)D7)14)21               – Push the literals 0, 7, 14, 21 onto the stack.
         WM     }       – Wrap the stack to a list and run each element on a separate
                          stack, collecting the results in a list.
           )IEt         – Crop the elements of the input before those indices.
               u        – Sum that list.
                 u      – Then sum the list of sums.
                  )70   – Push the literal 70 onto the stack.
                     s/ – Swap and divide.
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -pa, 28 bytes

$\+=$_/70*int$i++/7+1for@F}{

Try it online!

Input is space separated rather than comma separated.

\$\endgroup\$
1
  • \$\begingroup\$ You have $. available as the perfect multiplier. No need for $i \$\endgroup\$
    – Ton Hospel
    May 3, 2018 at 7:34
1
\$\begingroup\$

APL+WIN, 13 bytes

Prompts for array as a vector of integers:

(+/⎕×7/⍳4)÷70

Explanation:

7/⍳4) create a vector comprising 7 1s, 7 2s, 7 3s and 7 4s

+/⎕× prompt for input, multiply by the vector above and sum result

(....)÷70 divide the above sum by 70
\$\endgroup\$
1
\$\begingroup\$

Java 8, 57 bytes

a->{int r=0,i=35;for(;i-->7;)r+=i/7*a[i-7];return r/70d;}

Try it online.

Explanation:

a->{              // Method with integer-array parameter and double return-type
  int r=0,        //  Result-sum, starting at 0
      i=35;       //  Index-integer, starting at 35
  for(;i-->7;)    //  Loop `i` downwards in the range (35,7]
    r+=           //   Add the following to the result-sum:
       i/7        //    `i` integer-divided by 7,
       *a[i-7];   //    multiplied by the item at index `i-7`
  return r/70d;}  //  Return the result-sum, divided by 70.0
\$\endgroup\$
1
\$\begingroup\$

J, 16 bytes

70%~1#.]*7#4{.#\

Explanation:

              #\           finds the lengths of all successive prefixes (1 2 3 4 ... 28)
           4{.             takes the first 4 items (1 2 3 4)
         7#                creates 7 copies of each element of the above list
       ]*                  multiplies the input by the above 
    1#.                    sum
70%~                       divide by 70

Try it online!

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

Clojure, 48 46 bytes

#(/(apply +(for[i[0 7 14 21]v(drop i %)]v))70)

This ended up being shorter than mapcat + subvec combination.

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

TI-Basic, 25 bytes

mean(Ansseq(sum(I>{0,7,21,42}),I,1,70

Alternate solution, 39 bytes

Input L1
For(I,1,70
Ans+L1(I)sum(I>{0,7,21,42
End
Ans/70
\$\endgroup\$
1
\$\begingroup\$

Ruby, 65 bytes

->r{(b=(0..r.size/7).map{|a|r[a*7..-1]}.flatten).sum/b.size.to_f}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ The input size is specified to be fixed at 28 here - so you can save several bytes by hardcoding the values instead of using the size property. Try it online! \$\endgroup\$
    – Sundar R
    Jul 2, 2018 at 14:37
1
\$\begingroup\$

Excel, 36 33 bytes

-3 bytes thanks to @tsh.

=SUM(1:1,H1:AB1,O1:AB1,V1:AB1)/70

Input in first row (A1 to AB1).

\$\endgroup\$
1
  • \$\begingroup\$ Maybe A1:AB1 -> 1:1? \$\endgroup\$
    – tsh
    May 8, 2018 at 5:27
1
\$\begingroup\$

Julia 0.6, 27 bytes

p->repeat(1:4,inner=7)'p/70

Try it online!

The repeat call forms a column matrix of 28 values, containing seven 1's, then seven 2's, etc. We then transpose it with ', then do a matrix multiplication with the input (mutiplication is implicit here). Since it's a matrix multiplication of a 1x28 matrix with a 28x1 matrix, we end up with a single value, which is the weighted sum we need. Divide that by 70 to get our weighted mean.

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

Factor + math.unicode, 36 bytes

[ [ 7 /i 1 + * ] map-index Σ 70 / ]

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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