9
\$\begingroup\$

The challenge is to write a golf-code program that, given n positive real numbers from 0 to 10 (format x.y, y only can be 0 or 5: 0, 0.5, 1, 1.5, 2, 2.5 … 9.5 and 10), discard the lowest and highest values (only one, even though they are repeated) and shows the average of the remaining, in x.y format (y can be 0 or 5, rounded to closest), similar to some Olympic Games scoring.

Examples: Input -> Output

6 -> 6

6.5, 9 -> 8

9, 7, 8 -> 8

6, 5, 7, 8, 9 -> 7

5, 6.5, 9, 8, 7 -> 7

6.5, 6.5, 9.5, 8, 7 -> 7

5, 6.5, 7.5, 8.5, 9.5 -> 7.5

Notes: If the input is only two numbers, do not discard any, just average them. If the input is one number, the output is the same.

Clarifying the rounding rule (sorry, little confuse):

x.01 to x.25 round to x.0

x.26 to x.75 round to x.5

x.76 to x.99 round to x+1.0

\$\endgroup\$
17
  • 2
    \$\begingroup\$ How is the second example (6.5, 9 => 8) valid? If you throw out the high and the low, there are no values left to average? \$\endgroup\$ Commented Sep 13, 2019 at 17:38
  • 2
    \$\begingroup\$ Welcome to Code Golf SE! \$\endgroup\$ Commented Sep 13, 2019 at 17:43
  • 6
    \$\begingroup\$ I'd suggest we do not handle invalid input, the Olympics will have a fixed number of judges greater than two for such an event. (Diving removes the four extremities from seven for example) \$\endgroup\$ Commented Sep 13, 2019 at 17:54
  • 7
    \$\begingroup\$ Your example 6.5, 9 disagrees with your spec which indicates that x.75 rounds to x.5. \$\endgroup\$ Commented Sep 13, 2019 at 22:43
  • 7
    \$\begingroup\$ Until the rounding is sorted I’ve voted to close. \$\endgroup\$ Commented Sep 14, 2019 at 15:09

11 Answers 11

5
\$\begingroup\$

Jelly, 12 bytes

ṢṖḊȯµÆmḤær0H

Try it online!

    µ           Take
Ṣ               the input sorted,
 Ṗ              without its last
  Ḋ             or first element,
   ȯ            or the unchanged input if that's empty,
     Æm         then calculate the mean,
       Ḥ        double it,
        ær      round it to the nearest multiple of
          0     10^-0 (= 1),
           H    and halve it.

A version which rounds halves down, in accordance with the spec at the expense of the second test case:

Jelly, 12 bytes

ṢṖḊȯµÆmḤ_.ĊH

Try it online!

The rounding method here is closer to Jonathan Allan's:

Ḥ        Double,
 _       subtract
  .      one half,
   Ċ     round up,
    H    and halve.
\$\endgroup\$
4
  • \$\begingroup\$ Just so happens to accidentally comply with the update to the spec \$\endgroup\$ Commented Sep 13, 2019 at 18:15
  • \$\begingroup\$ @NickKennedy If I don't round, that case produces 6.8, which should round up to 7 according to the spec since 6.75 < 6.8 ≤ 7. \$\endgroup\$ Commented Sep 13, 2019 at 20:55
  • 1
    \$\begingroup\$ sorry one two many 7s. I meant [1,10,6,7,7,7] \$\endgroup\$ Commented Sep 13, 2019 at 22:39
  • 1
    \$\begingroup\$ Oh, yeah, it does do that one wrong. \$\endgroup\$ Commented Sep 13, 2019 at 22:40
4
\$\begingroup\$

Retina, 86 bytes

\.5
__
\d+
*4*__
O`_+
_+ (.+) _+
$1
O`.
^ *
$.&*__:
(_+):(\1{4})*(\1\1)?_*
$#2$#3*$(.5

Try it online! Link includes test cases. Explanation:

\.5
__
\d+
*4*__

Since Retina can't readily handle fractional or zero numbers, each number is represented in unary as 1 more than 4 times the value. The .5 therefore expands to 2 _s, while the *4*_ applies to the whole number part, and a final _ is suffixed.

O`_+

Sort the numbers into order.

_+ (.+) _+
$1

If there are at least three numbers, discard the first (smallest) and last (largest).

O`.

Sort the spaces to the start, thus also summing the numbers.

^ *
$.&*__:

Count the number of spaces and add _ and a separator. This then represents the number we have to divide by.

(_+):(\1{4})*(\1\1)?_*
$#2$#3*$(.5

Divide the sum by the number of numbers, allowing for the fact that we're working in multiples of 4 times the original number, so that the integer and decimal portions can be directly extracted. This is a truncating division, but fortunately because we added an extra _ to each number, the result effectively includes an extra 0.25, thus giving us the rounding we want.

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

EDIT: This answer has since become invalid. It was valid for about half a minute after it was posted.

Jelly, 10 bytes

ṢḊṖȯƊÆmḤḞH

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ seems to produce the wrong result for [6.5,9]. \$\endgroup\$ Commented Sep 13, 2019 at 18:17
  • 1
    \$\begingroup\$ @UnrelatedString At the moment I posted this, it was the correct output. Looks like OP has changed the rule now. \$\endgroup\$ Commented Sep 13, 2019 at 18:18
  • 1
    \$\begingroup\$ Yes, I made a mess, sorry :( \$\endgroup\$
    – JuanCa
    Commented Sep 13, 2019 at 18:19
  • 1
    \$\begingroup\$ As per my comment under Arnauld's post I basically had this algorithm too, so, after getting clarification on the rules, I've posted mine :) \$\endgroup\$ Commented Sep 13, 2019 at 18:19
  • 1
    \$\begingroup\$ @JonathanAllan Which is the same as Unrelated String's. :P \$\endgroup\$ Commented Sep 13, 2019 at 18:21
3
\$\begingroup\$

J, 36 35 bytes

[:(1r4<.@+&.+:+/%#)}:@}.^:(2<#)@/:~

Try it online!

Borrowed the double / floor / halve trick for rounding to 0.5 increments from Unrelated String.

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

Python 3, 62 bytes

def f(s):z=sorted(s)[1:-1]or s;return round(2*sum(z)/len(z))/2

Try it online!

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

JavaScript (V8), 213 211 189 176 bytes

Edit: -2 bytes because I ended with ;\n} when I could just end with a }, silly mistake.

Edit 2: -22 more bytes by reading about general JS golfing tips. I managed to take out parentheses from my nested ternaries in the r rounding function, and used bitwise math operations to avoid using Math.floor and Math.ceil

Edit 3: -13 bytes because I was able to replace the a.length shortcut function with just direct calls to a.length to save 4 bytes. I also moved the g() function directly into the return statement, since it was only used once, which removed the rest of the bytes.

a=>{s=i=>a.splice(i,1)
e=_=>a.reduce((t,i)=>t+=i)/a.length
r=n=>(m=n%1,m<0.75?m>0.25?~~(n)+0.5:~~(n):n%1?-~n:n)
return a.length>2?r((a.sort((x,y)=>x-y),s(0),s(-1),e())):r(e())}

Try it online!

I'm sure it can be improved as I'm fairly new, but it was fun to solve this one. I believe the main things that could be improved are my rounding logic/methods, and the fact that the main function uses a function body ({ } and return).

There was one thing in the question that was inconsistent with the examples and I wasn't really sure how to handle it. I implemented it so that it's consistent with the examples, but it doesn't exactly reflect the specified rounding rules, here is the example I found to be inconsistent:

6.5, 9 -> 8

You say it should be 8, although the average is 7.75. In the rounding rules you say it has to be at least .76 to go +1. I chose to reflect the examples instead of your rounding rules, so >=0.75 to go +1, and <=0.25 to go -1, between 0.25 and 0.75 (exclusive) for .5. If the rounding specifications change, my code should be able to adapt without changing the number of bytes, by just changing the numbers in the rounding function r, and maybe the order of the ternary statement depending on the rules.

Slightly ungolfed with explanation (the math operations were changed to bitwise operations and g() is directly in the return statement)

a => { // a is the input array
    s = i=>a.splice(i, 1); // shortcut to remove index i for 1 element
    e = _=>a.reduce((t, i) => t += i) / a.length; // get array avg
    g = _=>(a.sort((x,y)=>x-y), s(0), s(-1), e()); // what to execute when > 2: sort, remove 1st/last, get avg
    t = n=>Math.floor(n); // Math.floor shortcut

    // apply olympic rounding to number by checking the value of n%1
    r = n=>(m=n%1,m < 0.75 ? (m > 0.25 ? t(n) + 0.5 : t(n)) : Math.ceil(n));

    // if arr length > 2: round g(), otherwise round e()
    return a.length > 2 ? r(g()) : r(e());
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ I’ve posted a comment on the question about the discrepancy between the example and spec. \$\endgroup\$ Commented Sep 13, 2019 at 22:54
  • 1
    \$\begingroup\$ why you do not use l=a.length and everytime you want a length simply call l, here I do not know why you arr using function here \$\endgroup\$
    – Chau Giang
    Commented Sep 14, 2019 at 10:23
  • \$\begingroup\$ @chaugiang That would save the value, not a reference to a.length, so since I'm using it before & after operations that modify the array, l would become invalid as soon as the array is changed. LMK if wrong. It turns out it would actually save me 3 bytes now to just replace this with direct a.length calls. When I initially wrote it, I didn't know JS allowed you to use negative numbers for splice, so initially my second splice was s(l()-1) instead of just s(-1), and when I had 3 length calls it saved bytes to have this shortcut. Now it's no longer worth it. Thanks, will update! \$\endgroup\$
    – Matsyir
    Commented Sep 14, 2019 at 15:46
2
\$\begingroup\$

Jelly, 12 bytes

ṢṖḊȯ⁸ÆmḤ+.ḞH

A monadic Link accepting a list of numbers which yields a number.

Try it online!

How?

ṢṖḊȯ⁸ÆmḤ+.ḞH - Link, list of numbers, X
Ṣ            - sort X
 Ṗ           - remove the right-most
  Ḋ          - remove the left-most
    ⁸        - chain's left argument, X
   ȯ         - logical OR (if we have nothing left use X instead)
     Æm      - arithmetic mean
       Ḥ     - double
         .   - literal half
        +    - add
          Ḟ  - floor
           H - halve
\$\endgroup\$
6
  • 1
    \$\begingroup\$ @NickKennedy 34/5>6.75 \$\endgroup\$ Commented Sep 13, 2019 at 20:33
  • 1
    \$\begingroup\$ Sorry meant 1,10,7,7,7,6 where 27/4 = 6.75 \$\endgroup\$ Commented Sep 13, 2019 at 22:40
  • 1
    \$\begingroup\$ No the issue is the slightly unconventional rounding in the spec. In fact your answer also gets [1,10,7,6,6,6] wrong (it should be 6 not 6.5), while @UnrelatedString’s original version gets that one right because Python rounds to even (so 12.5 rounds down to 12). As I’ve now pointed out in a comment on the question, one of the examples also violates the rounding spec. Also note that fractions of powers of 2 shouldn’t be an issue for floating point inaccuracy because they have an exact binary representation. \$\endgroup\$ Commented Sep 14, 2019 at 14:52
  • 1
    \$\begingroup\$ I feel like the spec is awkward and possibly unintentional. (What does x.251 round to, etc; are the boundaries inclusive, exclusive, or is it up to us?) ...and then there is the comment "I realized it is a bit confuse, let's round them to the nearest, depending of the platform". Maybe we should VTC as unclear? \$\endgroup\$ Commented Sep 14, 2019 at 15:00
  • 1
    \$\begingroup\$ yes agree VTC for now \$\endgroup\$ Commented Sep 14, 2019 at 15:08
2
\$\begingroup\$

Brachylog, 19 bytes

o{bṀk|}⟨+/l⟩×₄<÷₂/₂

Try it online!

And I thought the rounding was awkward in Jelly!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is incorrect for [1,10,7,7,7,6]; 27/4 = 6.75 which should round to 6.5 according to spec. \$\endgroup\$ Commented Sep 13, 2019 at 22:42
2
\$\begingroup\$

Swift, 203 bytes

func a(b:[Double])->Void{var r=0.0,h=0.0,l=11.0
b.forEach{(c)in h=c>h ?c:h;l=c<l ?c:l;r+=c}
var d=Double(b.count)
r=d>2 ?(r-h-l)/(d-2.0):r/d
d=Double(Int(r))
r=r-d<=0.25 ?d:r-d<=0.75 ?d+0.5:d+1
print(r)}

Try it online!

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

PHP, 110 bytes

Seems like PHP has some good built-in functions for this. I just array_sum the whole thing, then if there's more than two elements, subtract the min() and max() values and divide by 2 less than the length of the array.

For the rounding, I use the round() function with the PHP_ROUND_HALF_DOWN flag (which = 2) on double the average, and then divide it by 2 so it goes in increments of 0.5

EDIT: for the case of [6.5, 9] I'm following the stated rule that 7.75 rounds to 7.5 and not 8 like in the original example given.

function s($s){$c=count($s);$t=array_sum($s);if($c>2){$c-=2;$t-=min($s)+max($s);}return round($t/$c*2,0,2)/2;}

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Well done! I wanted to post a PHP answer but the rules had many flaws or changes that I just gave up! I tweaked your code a little and saved 10 bytes: Try it online! \$\endgroup\$
    – Night2
    Commented Sep 14, 2019 at 5:48
2
\$\begingroup\$

Zsh --force_float, 141 136 109 96 bytes

Try it online!  109bytes  136bytes  141bytes

n=$1;for x ((t+=x,m=x>m?x:m,n=x<n?x:n,s=2*(#>2?(t-m-n)/(#-2):t/#)))
<<<$[(s^0+(s-s^0>.5?1:0))/2]

Solution follows latest spec, except for the unclear second test case. Saved a few bytes using implicit ($@). Saved more by moving most calculations into the (( )) statement.

We implicitly iterate over the arguments with for x, and build a running total t, and also find maxima, minima m, n. If the number of arguments # is greater than 2, we discard m and n from the average. s is 2x the resulting average. If the mantissa of s is greater than 0.5, round s up, otherwise truncate with s^0. Finally, divide by 2 and output.

\$\endgroup\$

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