8
\$\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\$

closed as unclear what you're asking by Nick Kennedy, Jonathan Allan, Stephen, Erik the Outgolfer, Arnauld Sep 14 at 16:51

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 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\$ – Jeff Zeitlin Sep 13 at 17:38
  • 2
    \$\begingroup\$ Welcome to Code Golf SE! \$\endgroup\$ – AdmBorkBork Sep 13 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\$ – Jonathan Allan Sep 13 at 17:54
  • 7
    \$\begingroup\$ Your example 6.5, 9 disagrees with your spec which indicates that x.75 rounds to x.5. \$\endgroup\$ – Nick Kennedy Sep 13 at 22:43
  • 7
    \$\begingroup\$ Until the rounding is sorted I’ve voted to close. \$\endgroup\$ – Nick Kennedy Sep 14 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\$
  • \$\begingroup\$ Just so happens to accidentally comply with the update to the spec \$\endgroup\$ – Unrelated String Sep 13 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\$ – Unrelated String Sep 13 at 20:55
  • 1
    \$\begingroup\$ sorry one two many 7s. I meant [1,10,6,7,7,7] \$\endgroup\$ – Nick Kennedy Sep 13 at 22:39
  • 1
    \$\begingroup\$ Oh, yeah, it does do that one wrong. \$\endgroup\$ – Unrelated String Sep 13 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\$
  • \$\begingroup\$ seems to produce the wrong result for [6.5,9]. \$\endgroup\$ – Unrelated String Sep 13 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\$ – Erik the Outgolfer Sep 13 at 18:18
  • 1
    \$\begingroup\$ Yes, I made a mess, sorry :( \$\endgroup\$ – JuanCa Sep 13 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\$ – Jonathan Allan Sep 13 at 18:19
  • 1
    \$\begingroup\$ @JonathanAllan Which is the same as Unrelated String's. :P \$\endgroup\$ – Erik the Outgolfer Sep 13 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\$

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\$
  • 1
    \$\begingroup\$ I’ve posted a comment on the question about the discrepancy between the example and spec. \$\endgroup\$ – Nick Kennedy Sep 13 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 Sep 14 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 Sep 14 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\$
  • 1
    \$\begingroup\$ @NickKennedy 34/5>6.75 \$\endgroup\$ – Jonathan Allan Sep 13 at 20:33
  • 1
    \$\begingroup\$ Sorry meant 1,10,7,7,7,6 where 27/4 = 6.75 \$\endgroup\$ – Nick Kennedy Sep 13 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\$ – Nick Kennedy Sep 14 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\$ – Jonathan Allan Sep 14 at 15:00
  • 1
    \$\begingroup\$ yes agree VTC for now \$\endgroup\$ – Nick Kennedy Sep 14 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
    \$\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\$ – Nick Kennedy Sep 13 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
    \$\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 Sep 14 at 5:48
2
\$\begingroup\$

Zsh, 141 136 bytes

try it online!   141bytes

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

Solution follows latest spec. Saved a few bytes using implicit ($@).

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 a 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\$
2
\$\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\$

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