# Calculate the average and standard deviation, rubiks cube style

## Introduction

When solving a rubiks cube, one often write down the times like this

11.91, (11.28), (12.32)


This is called a average of 3, while a average of 5 looks like this

13.36, (11.89), 12.31, (16.44), 12.26


Note how the worst and best times have parenthesis around them. When calculating the average of 5 these times are removed. For an average of 3 the worst and best times are NOT removed. Similarly when calculating the standard deviation.

When taking the average of more than 12 cubes things start to get a bit harder. The general rule of thumb is:

When solving fewer than 5 cubes, do not remove any times when calculating avg or std

When evaluating fewer than 12 times, remove the best and worst time when calculating avg or std

When evaluating fewer than 40 times remove the 1/12 worst and 1/12 best times rounded down the nearest integer.

When evaluating more than 40 times remove the 1/20 worst times and the 1/20 best times rounded down to the nearest integer.

For an average of 100 this would mean we would remove the (100/20) = 5 best solves and (100/20) = 5 worst solves. Giving

14.88, 12.28, 13.76, 16.06, 13.82, 13.26, 14.57, 12.56, 15.02, 14.73,
13.87, 14.59, 15.17, (18.48), 12.09, 12.76, 11.65, 14.14, 12.83, 14.30,
13.28, 14.02, 12.55, 15.18, 13.65, 12.72, 14.86, 14.08, 15.07, 12.88, 13.78,
13.88, 14.63, 12.72, (10.10), 14.70, 12.82, 13.27, 13.82, 14.74, (11.22),
13.46, 12.66, 14.06, (10.58), 15.06, (18.27), 13.39, (17.88), (18.67),
15.38, 15.60, 14.24, 12.64, 15.51, 14.23, 16.71, 14.55, 14.32, 12.33, 11.90,
13.65, 13.69, 13.90, 13.15, (9.61), 12.91, 13.39, 11.77, 12.64, 15.22,
14.69, 12.76, 15.10, 11.91, (11.28), 12.32, 14.28, 14.46, 14.66, 14.15,
15.27, (17.73), 12.70, 14.58, 11.84, 13.25, 13.36, 13.26, 15.72, 14.15,
12.77, 15.26, 12.87, 12.96, 13.57, 14.50, 14.30, 14.57, 12.69


## The challenge

The problem at hand is to take a (large) list of numbers and figure out the best average or std of a subset of these.

input

list, n, avg or std


Write a program that takes in a list of numbers formated exactly as comma seperated numbers 12.91, 13.39, ... or [12.91, 13,39 ... ] You can assume that the list only contains real valued positive numbers less than 2^32.

A number n indicating how many numbers to average or take the std of, if n=0 one should take the average / std of all the numbers.

A string avg or std indicating if one should return the lowest average of n numbers or the lowest standard deviation (std). A negative n or a non integer should throw an error, blank or return false.

Output

The output should be exactly on the form

avg = ...
list of of numbers


or

std = ...
list of of numbers


As shown in the examples. Note that the best and worst times are marked with brackets as given by the rules above. The function should return the n consecutive times with the lowest avg or std At every 12 time, a newline should be inserted.

## Test case

I will use the following list of 200 numbers to base my tests on

15.86, 17.02, 24.01, 21.01, 15.93, 14.86, 18.43, 12.52, 18.48, 19.85, 13.01, 14.92, 13.07, 13.44, 13.07, 15.08, 12.70, 13.59, 15.22, 11.88, 13.26, 13.62, 12.85, 16.88, 15.78, 15.94, 14.88, 12.28, 13.76, 16.06, 13.82, 13.26, 14.57, 12.56, 15.02, 14.73, 13.87, 14.59, 15.17, 18.48, 12.09, 12.76, 11.65, 14.14, 12.83, 14.30, 13.28, 14.02, 12.55, 15.18, 13.65, 12.72, 14.86, 14.08, 15.07, 12.88, 13.78, 13.88, 14.63, 12.72, 10.10, 14.70, 12.82, 13.27, 13.82, 14.74, 11.22, 13.46, 12.66, 14.06, 10.58, 15.06, 18.27, 13.39, 17.88, 18.67, 15.38, 15.60, 14.24, 12.64, 15.51, 14.23, 16.71, 14.55, 14.32, 12.33, 11.90, 13.65, 13.69, 13.90, 13.15, 9.61, 12.91, 13.39, 11.77, 12.64, 15.22, 14.69, 12.76, 15.10, 11.91, 11.28, 12.32, 14.28, 14.46, 14.66, 14.15, 15.27, 17.73, 12.70, 14.58, 11.84, 13.25, 13.36, 13.26, 15.72, 14.15, 12.77, 15.26, 12.87, 12.96, 13.57, 14.50, 14.30, 14.57, 12.69, 15.21, 14.45, 14.90, 14.91, 15.66, 15.87, 14.79, 15.69, 17.37, 15.42, 12.11, 14.89, 13.39, 12.62, 13.42, 14.07, 14.85, 13.23, 14.05, 14.43, 13.36, 14.19, 14.16, 14.66, 12.02, 12.56, 12.69, 12.55, 14.36, 15.79, 12.53, 12.51, 12.15, 15.60, 13.42, 12.87, 13.02, 15.66, 13.18, 14.77, 13.57, 13.86, 12.26, 14.48, 14.68, 11.85, 14.82, 13.74, 13.85, 15.05, 14.78, 14.43, 12.72, 14.39, 15.06, 15.28, 12.06, 14.59, 15.49, 11.66, 14.83, 14.09, 11.62, 15.96, 14.77, 14.99, 14.20, 12.35, 17.62, 11.66, 13.46, 15.24, 14.85, 13.48


Input 0:

list, 3, avg


Output 0:

avg = 11.84
11.91, (11.28), (12.32)


Input 1:

list, 12, avg


Output 1:

avg = 12.88
(9.61), 12.91, 13.39, 11.77, 12.64, (15.22), 14.69, 12.76, 15.10, 11.91, 11.28, 12.32


Input 2:

list, 12, std


Output 2:

std = 0.44
15.21, 14.45, 14.90, 14.91, 15.66, 15.87, 14.79, 15.69, (17.37), 15.42, (12.11), 14.89


Input 3:

list, 0, std


Output 3:

std = 1.21
15.86, 17.02, (24.01), (21.01), 15.93, 14.86, (18.43), 12.52, (18.48), (19.85), 13.01, 14.92,
13.07, 13.44, 13.07, 15.08, 12.70, 13.59, 15.22, 11.88, 13.26, 13.62, 12.85, 16.88,
15.78, 15.94, 14.88, 12.28, 13.76, 16.06, 13.82, 13.26, 14.57, 12.56, 15.02, 14.73,
13.87, 14.59, 15.17, (18.48), 12.09, 12.76, (11.65), 14.14, 12.83, 14.30, 13.28, 14.02,
12.55, 15.18, 13.65, 12.72, 14.86, 14.08, 15.07, 12.88, 13.78, 13.88, 14.63, 12.72,
(10.10), 14.70, 12.82, 13.27, 13.82, 14.74, (11.22), 13.46, 12.66, 14.06, (10.58), 15.06,
(18.27), 13.39, (17.88), (18.67), 15.38, 15.60, 14.24, 12.64, 15.51, 14.23, 16.71, 14.55,
14.32, 12.33, 11.90, 13.65, 13.69, 13.90, 13.15, (9.61), 12.91, 13.39, (11.77), 12.64,
15.22, 14.69, 12.76, 15.10, 11.91, (11.28), 12.32, 14.28, 14.46, 14.66, 14.15, 15.27,
(17.73), 12.70, 14.58, 11.84, 13.25, 13.36, 13.26, 15.72, 14.15, 12.77, 15.26, 12.87,
12.96, 13.57, 14.50, 14.30, 14.57, 12.69, 15.21, 14.45, 14.90, 14.91, 15.66, 15.87,
14.79, 15.69, 17.37, 15.42, 12.11, 14.89, 13.39, 12.62, 13.42, 14.07, 14.85, 13.23,
14.05, 14.43, 13.36, 14.19, 14.16, 14.66, 12.02, 12.56, 12.69, 12.55, 14.36, 15.79,
12.53, 12.51, 12.15, 15.60, 13.42, 12.87, 13.02, 15.66, 13.18, 14.77, 13.57, 13.86,
12.26, 14.48, 14.68, 11.85, 14.82, 13.74, 13.85, 15.05, 14.78, 14.43, 12.72, 14.39,
15.06, 15.28, 12.06, 14.59, 15.49, (11.66), 14.83, 14.09, (11.62), 15.96, 14.77, 14.99,
14.20, 12.35, 17.62, (11.66), 13.46, 15.24, 14.85, 13.48


Split the lines at every 12 number.

Input 4:

list, 201, avg


Output 5:

Throw Error or False.


Input 6:

list, 1, avg


Output 6:

avg = 9.61
(9.61)


Input 8:

list, 1, std


Output 8:

std = 0
(15.86)


just return the first element of the list.

# Scoring

Submissions will be scored in bytes. I recommend this website to keep track of your byte count, though you can use any counter you like. Like always whitespace counts as bytes.

Remove 25% of your byte count if your function has the ability to switch between highest avg and std, and lowest avg and std. Eg input on the form

list, n, avg / std, high / low


This is , so the lowest score wins!

• Can a function be written? Commented Dec 5, 2015 at 12:15
• yeah =) No problem Commented Dec 5, 2015 at 12:28
• This is an old post, but I have some questions. Why is output 0 not 10.10? (The 3 lowest values in your example list are [9.61, 10.10, 10.58].) Why are multiple values in parentheses in output 3? (The description just says that those are the "smallest" and "largest", but that's not the case.) Finally, why is output 8 zero? The standard deviation of only 1 number is undefined (because it involves division by zero). I think I have a neat solution to this puzzle, but I'm not sure because the details are so vague... Commented Oct 2, 2016 at 16:12

# Java 10, 944903 861 bytes

import java.util.*;interface M{static void main(String[]a){var f=a[2];int n=new Short(a[1]),i=0,l,j,k;if(n<0)return;List<Double>L=new Stack(),t,r,R=L,u,U=L,S=L,V=L;for(var s:a[0].split(","))L.add(new Double(s));l=L.size();n=n<1?l:n;i=0;double m=99,M=m,q,Q,x,y,z;do{for(t=new Stack(),x=y=j=0;j<n;)t.add(L.get(i+j++));for(k=n<12?0:n<40?n/12:n/20,j=k=k<1?1:k,u=new ArrayList(t),r=new Stack();j-->0;){r.add(q=Collections.min(t));r.add(Q=Collections.max(t));if(n>4){t.remove(q);t.remove(Q);}}for(var T:t)x+=T;x/=k=n>4?n-2*k:n;if(x<m){m=x;R=r;U=u;}for(var T:t)y+=(z=T-x)*z;y=Math.sqrt(y/k);if(y<M){M=y;S=r;V=u;}}while(i++<l-n);j=f.charAt(0)-97;System.out.println(f+" = "+f.format(f="%.2f",q=j<1?n<2?Collections.min(L):m:n<2?0:M));i=0;for(var o:j<1?U:n<2?L.subList(0,1):V)System.out.print(f.format((j<1?R:S).remove(o)?"(%.2f)":f,n+j<2?q:o)+(++i<n&i%12>0?", ":"\n"));}}


Full program requirement, strict I/O formatting, validating.. sigh.. >.>

Verify all test cases: 3,avg ; 12,avg ; 12,std ; 0,std ; 201,avg ; 1,avg ; 1,std ; -1,either.

Here is the same as function with somewhat flexible I/O and without validating (still 776 739 719 705 bytes..):

import java.util.*;(L,n,f)->{int i=0,l=L.size(),j,k;List<Double>t,r,R=new Stack(),u,U=R,S=R,V=R;n=n<1?l:n;double m=99,M=m,q,Q,x,y,z;do{for(t=new Stack(),x=y=j=0;j<n;)t.add(L.get(i+j++));for(k=n<12?0:n<40?n/12:n/20,j=k=k<1?1:k,u=new ArrayList(t),r=new Stack();j-->0;){r.add(q=Collections.min(t));r.add(Q=Collections.max(t));if(n>4){t.remove(q);t.remove(Q);}}for(var T:t)x+=T;x/=k=n>4?n-2*k:n;if(x<m){m=x;R=r;U=u;}for(var T:t)y+=(z=T-x)*z;y=Math.sqrt(y/k);if(y<M){M=y;S=r;V=u;}}while(i++<l-n);j=f.charAt(0)-97;System.out.println(f+" = "+f.format(f="%.2f",q=j<1?n<2?Collections.min(L):m:n<2?0:M));for(var o:j<1?U:n<2?L.subList(0,1):V)System.out.print(f.format((j<1?R:S).remove(o)?"(%.2f)":f,n+j<2?q:o)+" ");}


-20 bytes thanks to @ceilingcat.

Try it online.

Explanation:

import java.util.*;           // Required import for List, Stack and Collections
interface M{                  //  Class
static void main(String[]a){//   Mandatory main-method
var f=a[2];               //    Save the third argument in String f
int n=new Short(a[1]),    //    Save the second argument as integer in n
i=0,l,j,k;            //    Some temp/index integers
if(n<0)return;            //    If n is negative: stop the program
List<Double>L=new Stack(),//    Input-List, starting empty
t,r,R=L,u,U=L,S=L,V=L;
//    Some temp Lists
for(var s:a[0].split(","))//    Loop over the input-items as Strings
L.add(new Double(s));   //     Convert them to doubles, and add them to the List
l=L.size();               //    Set l to the amount of items
n=n<1?l:n;                //    If n was 0, make it equal to l instead
double m=99,M=m,          //    Lowest avg and std, both starting at 99
q,Q,x,y,z;         //    Some temp floats
do{                       //    Start the do-while:
for(t=new Stack(),      //     Reset List t
x=y=j=0;j<n;)       //     Loop j in the range [0, n):
t.add(L.get(i+j++));  //      And add the items on index i+j of List L to t
for(k=n<12?             //     If n is smaller than 12
0                //      Set k to 0
:n<40?            //     Else-if n is in the range [12; 40)
n/12             //      Set k to 1/12th of n
:                 //     Else (n is 40 or larger)
n/20,            //      Set k to 1/20th of n
j=k=k<1?1:k,        //     If k is 0 due to rounding, make it 1 instead
u=new ArrayList(t), //     Copy List t to u
r=new Stack();      //     And reset List r
j-->0;){            //     Loop k amount of times:
//      Add the smallest item in List t to r
//      as well as the largest item
if(n>4){              //      If n is 5 or larger:
t.remove(q);t.remove(Q);}}
//       Remove those two items from List t
for(var T:t)            //     Loop over List t:
x+=T;                 //      And sum them all into value x
x/=k=n>4?               //     If n is 5 or larger
n-2*k               //      Set k to n-2*k and divide x by that
:                    //     Else:
n;                  //      Set k to n and divide x by that
if(x<m){                //     If x is smaller than the previous smallest avg m
m=x;                  //      Replace m with x (smallest avg)
R=r;                  //      Replace R with r (items between parenthesis)
U=u;}                 //      And replace U with u (all n items in this avg)
for(var T:t)            //     Loop over List t again:
y+=(z=T-x)*z;         //      And sum (T-x)**2 to y
y=Math.sqrt(y/k);       //     Also divide y by k, and take its square-root
//     The process above is how you calculate the std
if(y<M){                //     If y is smaller than the previous smallest std M:
M=y;                  //      Replace M with y (smallest std)
S=r;                  //      Replace S with r (items between parenthesis)
V=u;}}                //      And replace V with u (all n items in this std)
while(i++<l-n);           //    Continue the do-while as long as i is smaller than l-n
j=f.charAt(0)-97;         //    Set j to the alphabetic index of the first letter of f
System.out.println(f+" = "//    Print "f = "
+f.format(f="%.2f",     //     Round to two decimals
q=j<1?                //     If it's an avg:
n<2?               //      And n is 1:
Collections.min(L)//       Simply take the smallest value in L
:                  //      Else:
m                 //       Take the calculated lowest avg m
:                   //     Else (it's an std):
n<2?               //      If n is 1:
0                 //       Use 0
:                  //      Else:
M));              //       Take the calculated lowest std M
i=0;                      //    Reset i to 0
for(var o:j<1?            //    If it's an avg:
U              //     Loop over List U
:               //    Else (it's an std instead):
n<2?           //     If n is 1:
L.subList(0,1)//      Only take the first item of List L
:              //     Else:
V)            //      Loop over List V
System.out.print(f.format(
(j<1?                   //    If it's an avg:
R                     //     Use List R
:                      //    Else (it's an std instead):
S)                    //     Use List S
.remove(o)?         //    If the current item is in this List:
"(%.2f)"          //     Round to two decimals, and add parenthesis
:                  //    Else:
f,                //     Only round to two decimals
n+j<2?                  //    If it's an avg, and n is 1:
q                      //     Take the smallest value in L
:                       //    Else:
o)                     //     Take the current item in this loop
+(++i<n              //    If it's not the last item,
&i%12>0?      //    and also not the 12th item of the row:
", "               //     Append a comma and space as separator
:                   //    Else:
"\n"));}}          //     Append a newline instead


# 05AB1E, score: 85.5 (114 bytes - 25% bonus)

† Could be score: 83.25 (111 bytes - 25% bonus) by removing 2.ò (which rounds the output avg/std to 2 decimals). This isn't mentioned in the challenge rules, but since everything else about the I/O is so strict and rounding to two decimals is also done by the WCA (World Cube Association), I've just included it.

DŒsgI‚²ĀèDUùεƵJü2XŽ4Ý2ô@ÏXšzX*òθFDWsà‚vyD…(ÿ).;}}Dʒ'(å≠X5‹~}žuмDÅA©-nÅAt®‚³Çθè‚}Σθ}|θÇнƵ7.Sè2.ò³'=‚sªs12ô»»¹gÝ²å×


Also supports low vs high as fourth input. At the cost of just 8 bytes (|θÇнƵ7.Sè instead of н), this was well worth the 25% bonus.
Outputs an empty string for invalid $$\n\$$.

Explanation:

D                    # Duplicate the first (implicit) input-list
Œ                   # Pop the copy, and get all its sublists
sgI‚²Āè            # Transform n=0 to n=listLength
s                  #  Swap so the first input-list is at the top again
g                 #  Pop and push its length
I‚               #  Pair it with the second input-integer n
²              #  Push the second input-integer n again
Ā             #  Check whether it's NOT 0 (0 if 0; 1 otherwise)
è            #  0-base index this into the pair
DU          # Store a copy in variable X
ù         # Only keep the subslist of that size
ε                    # Map over each sublist
ƵJü2XŽ4Ý2ô@ÏXšzX*òθ #  Determine how many lowest/highest numbers we should surround
#  with parenthesis:
ƵJ                  #   Push compressed integer 120
ü2                #   Get its overlapping pairs: [12,20]
X               #   Push value X
Ž4Ý            #   Push compressed integer 1240
2ô          #   Split it into pairs: [12,40]
@         #   >= check on X: [X>=12,X>=40]
Ï        #   Keep the [12,20]-values at the truthy indices
Xš      #   Prepend X itself to this list
z     #   Calculate 1/v for each value in this list
X*   #   Multiply each by X
ò  #   Round each to the nearest integer
θ #   Pop and keep the last one
F                   #  Loop that many times:
D                  #   Duplicate the current sublist
W                 #   Push its minimum (without popping)
#   (will ignore values already wrapped in parenthesis)
s                #   Swap so the copy of the sublist is at the top again
à               #   Pop and push its maximum
#   (will ignore values already wrapped in parenthesis)
‚              #   Pair this minimum and maximum together
v             #   Loop over this pair:
yD           #    Push the min or max twice
…(ÿ)       #    Surround the top copy in parenthesis
.;     #    Replace the first occurrence of this value in the sublist
}             #   Close the [min,max]-loop
}                   #  Close the other loop
D                  #  Duplicate the modified sublist
ʒ                 #  Filter the copy by:
'(å≠            '#   Check that the current value does NOT contain parenthesis
~         #   OR
X5‹          #   Whether X is smaller than 5
}                 #  Close the filter
žu               #  Push constant string "()<>[]{}"
м              #  Remove all those characters from each value within the list
#  (only applies if X is smaller than 5)
DÅA©-nÅAt®‚        #  Pop this list, and push its [std,avg] pair:
D                  #   Duplicate this list
ÅA                #   Pop the copy, and get its average
©               #   Store this average in variable ® (without popping)
-              #   Subtract this average from each value in the list
n             #   Square each
ÅA           #   Take the average of this list again
t          #   Take the square-root of that
®‚        #   And pair this std with the average ®
³                  #  Push the third input-string
Ç                 #  Convert it to a list of codepoint integers
#  ("avg"=[97,118,103]; "std"=[115,116,100])
θ                #  Pop and push the last value ("avg"=103; "std"=100)
è               #  Use that to 0-based modular index into the pair of [std,avg]
‚              #  And pair it together with the modified list
}                    # Close the map
Σ                   # Sort this list by:
θ                  #  The last item of the pair (the avg or std)
}                   # Close the sort-by
|                  # Get a list of all remaining inputs: [third,fourth]
θ                 # Pop and keep its last item (the fourth input)
# (|θ cannot be I, since ³ won't add the third input to the
# input history)
Ç                # Convert it to a list of codepoint integers as well
# ("low"=[108,111,119]; "high"=[104,105,103,104])
н               # Pop and push the first value ("low"=108; "high"=104)
Ƶ7             # Push compressed integer 108
.S           # Compare: -1 if <108; 0 if ==108; 1 if >108
# (aka "low"=0; "high"=-1)
è          # Use that to 0-based modular index into the sorted list
# (where -1 will take the last/highest item)
# Pop the pair and push its contents to the stack
2.ò                 # Round the avg/std to 2 decimals†
³                # Push the third input-string again
'=‚            '# Pair it with an "="
sª           # Swap and append the rounded avg/std
s                   # Swap so the list is at the top
12ô                # Split it into parts of size 12
»               # Join each inner list by spaces, and then each string by newlines
»          # Join the two strings on the stack with newline delimiter
¹gÝ²å×               # Transform it to an empty string if n is invalid:
¹g                   #  Push the length of the first input-list
Ý                  #  Pop and push a list in the range [0,listLength]
²å                #  Check if the second input n is in this list
#  (1 if truthy; 0 if falsey)
×               #  Repeat the string that many times
# (after which the result is output implicitly)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why ƵJ is 120; Ž4Ý is 1240; and Ƶ7 is 108.