Rank a list of integers

22

1

You're given a non-empty list of positive integers, e.g.

[6 2 9 7 2 6 5 3 3 4]

You should rank these numbers by their value, but as is usual in leaderboards, if there is a tie then all the tied numbers get the same rank, and an appropriate number of ranks is skipped. The expected output for the above list would therefore be

[3 9 1 2 9 3 5 7 7 6]

For example, the highest value in the input was 9, so this becomes a 1 (first rank). The third highest value is 6, so both 6s become 3, and the rank 4 is skipped entirely.

Rules

You can use any convenient, unambiguous, flat list format for input and output. The first/smallest rank in the output should always be 1.

You may write a program or a function and use any of the our standard methods of receiving input and providing output.

You may use any programming language, but note that these loopholes are forbidden by default.

This is , so the shortest valid answer – measured in bytes – wins.

Test Cases

[8] -> [1]
[1 15] -> [2 1]
[18 14 11] -> [1 2 3]
[11 16 14 8] -> [3 1 2 4]
[15 15 15 15 15] -> [1 1 1 1 1]
[10 2 5 4 15 5] -> [2 6 3 5 1 3]
[5 5 10 10 5 11 18] -> [5 5 3 3 5 2 1]
[2 4 9 4 17 9 17 16] -> [8 6 4 6 1 4 1 3]
[11 17 19 17 10 10 15 3 18] -> [6 3 1 3 7 7 5 9 2]
[2 11 4 8 3 3 12 20 4 18] -> [10 4 6 5 8 8 3 1 6 2]
[12 6 10 2 19 19 6 19 8 6 18] -> [5 8 6 11 1 1 8 1 7 8 4]
[5 6 14 19 13 5 19 9 19 9 9 19] -> [11 10 5 1 6 11 1 7 1 7 7 1]
[9 2 12 3 7 11 15 11 6 8 11 17 11] -> [8 13 3 12 10 4 2 4 11 9 4 1 4]
[3 5 15 7 18 5 3 9 11 2 18 1 10 19] -> [11 9 4 8 2 9 11 7 5 13 2 14 6 1]
[6 11 4 19 14 7 13 16 10 12 7 9 7 10 10] -> [14 6 15 1 3 11 4 2 7 5 11 10 11 7 7]
[11 20 11 1 20 16 11 11 4 8 9 7 11 14 10 14] -> [6 1 6 16 1 3 6 6 15 13 12 14 6 4 11 4]
[4 7 15 2 3 2 3 1 14 2 10 4 7 6 11 2 18] -> [9 6 2 13 11 13 11 17 3 13 5 9 6 8 4 13 1]
[5 1 17 7 1 9 3 6 9 7 6 3 2 18 14 4 18 16] -> [12 17 3 8 17 6 14 10 6 8 10 14 16 1 5 13 1 4]
[5 6 8 10 18 13 20 10 7 1 8 19 20 10 10 18 7 2 1] -> [16 15 11 7 4 6 1 7 13 18 11 3 1 7 7 4 13 17 18]
[12 17 8 2 9 7 15 6 19 5 13 16 14 20 10 11 18 4 3 1] -> [9 4 13 19 12 14 6 15 2 16 8 5 7 1 11 10 3 17 18 20]

Martin Ender

Posted 2016-12-08T19:12:07.663

Reputation: 184 808

1Closely related. The difference is that that challenge guarantees that the input is sorted, which means that most answers rely on a form of indexOf function. I believe for unsorted input there are shorter alternatives in many languages. – Martin Ender – 2016-12-08T19:13:12.087

3Also related – Lynn – 2016-12-08T21:55:07.493

Im sorry, but I believe that this is too close to Lynn's link. The differences are minimal: The values are truncated, you can't assume an already-sorted input and half of the output has its order swapped. The accepted answer on the linked question nearly works. With minimal effort, someone could make it work. As such, I stand that this is a duplicated. – Ismael Miguel – 2016-12-09T18:25:13.947

I disagree, this is clearly not a duplicate. – Timtech – 2016-12-09T21:24:04.713

I agree with timtech, this challenge is simpler, but not a duplicate. – tuskiomi – 2016-12-09T21:53:38.680

Answers

13

Workaround in Excel for silly Rules Regarding Mouse Inputs on Code Golf Stack Exchange: (WESRRMICGSE) 28 bytes

rank(RC[1],r1c1:r1024:c1024)

Input list as csv (10,23,34,2,) into the compiler after entering the source. no quotes, no brackets, trailing comma.

WESRRMICGSE is exactly like programming in excel, except you can omit the initial '=' sign to save a byte. The difference in functionality comes from the fact that WESRRMICGSE will either drag the formula down to copy the code automatically and provide different outputs provided with a single integer input. provided a list as input, that list goes into the B column (input column), and the formula is drug down automatically to match the number of inputs. (eg: the input 34,21,45, would 'drag' the formula down 2 cells, for a total of 3 cells with the formula).

Edit: I never expected this answer to be popular. Wow!

tuskiomi

Posted 2016-12-08T19:12:07.663

Reputation: 3 113

21The language name is a bit obnoxious... – Conor O'Brien – 2016-12-08T19:22:59.413

What rules do you refer and how exactly are they silly? – Luis Mendo – 2016-12-08T21:21:51.187

3

@LuisMendo the rules declared here: http://meta.codegolf.stackexchange.com/questions/10199/what-mouse-interactions-are-allowed-by-default-as-part-of-input-output I think the rule is silly because I took 5 minutes to write an 'interpreter' that circumvents exactly what they are talking about. The more that this language can be used in challenges, the sillier the rule becomes. I'll be sure to include this in the link.

– tuskiomi – 2016-12-08T21:27:30.730

11

MATL, 4 bytes

&<sQ

Try it online! Or verify all test cases.

Explanation

&<   % Input array implicitly. Matrix of all pairwise "less than" comparisons
s    % Sum of each column
Q    % Add 1. Display implicitly

Luis Mendo

Posted 2016-12-08T19:12:07.663

Reputation: 87 464

9

Python 2, 41 bytes

lambda l:map(sorted(l+[l])[::-1].index,l)

For each value, find its index in the list sorted by decreasing order. To make the largest value give 1 instead of 0, we use an extra "infinity" element of the list itself, since Python 2 treats lists as bigger than numbers.

A more direct solution is 42 bytes and also works in Python 3.

lambda l:[1+sum(y<x for x in l)for y in l]

For each element, counts the number of smaller elements, adding 1 to shift to 1-indexed.

xnor

Posted 2016-12-08T19:12:07.663

Reputation: 115 687

8

Jelly, 5 bytes

ṢṚiЀ

Try it online!

How it works

ṢṚiЀ  Main link. Argument: A (array)

ṢṚ     Sort and reverse A.
  iЀ  Find the index of each n in A in the previous result.

Dennis

Posted 2016-12-08T19:12:07.663

Reputation: 196 637

7

R, 24 25 20 bytes

Uses the standard rank function with the "min" ties method over the negated vector. cat added to output it to STDOUT. Saved one thanks to @Guiseppe

cat(rank(-scan(),,"mi"))

Example

> cat(rank(-scan(),,"mi"))
1: 9 2 12 3 7 11 15 11 6 8 11 17 11
14: 
Read 13 items
8 13 3 12 10 4 2 4 11 9 4 1 4
> 

MickyT

Posted 2016-12-08T19:12:07.663

Reputation: 11 735

I think you need to wrap it in cat for it to be a full program. – Alex A. – 2016-12-10T19:56:47.207

@AlexA. I was wondering about that. Would it be fair to say that this is a function in it's own right and in that case would rank(-a,,'min') be ok where a is the list input in vector form? – MickyT – 2016-12-11T21:29:25.620

In that case we would consider it a snippet, because it assumes that a variable already exists in the namespace. To make it a proper function submission you'd need function(a)rank(-a,,'min'). – Alex A. – 2016-12-13T03:39:34.530

can be shortened to just "mi" rather than "min". – Giuseppe – 2017-10-22T13:41:16.337

@AlexA. why does it need to be wrapped in cat? If the submission had been function(a)rank(-a,,'mi') that would be considered sufficient and the program output is identical to rank(-scan(),,'mi') – Mark – 2017-11-13T04:10:28.070

4

PowerShell v2+, 43 41 bytes

($a=$args)|%{@($a|sort -d).indexof($_)+1}

Developed independently, but I see that this is the same algorithm as @xnor's Python solution, so /shrug.

Takes input as individual command-line arguments (i.e., a space separated list). Output (default formatting) is a newline between elements.

For each element in the input list, it sorts the input list in -descending order, takes the .indexOf() the current element, and adds 1. Note the explicit array cast @(...) in order to account for a single-digit input. The resulting numbers are left on the pipeline and output is implicit.

Saved 2 bytes thanks to @Matt!

Example

PS C:\Tools\Scripts\golfing> .\rank-the-integers.ps1 6 2 9 7 2 6 5 3 3 4
3
9
1
2
9
3
5
7
7
6

AdmBorkBork

Posted 2016-12-08T19:12:07.663

Reputation: 41 581

Is there a reason sort -d didn't work for you? That is unambiguous for me. – Matt – 2016-12-10T05:33:52.187

@Matt Odd. On my Win8.1 ISE, it states that -Descending and -Debug are ambiguous. But in the straight shell on Win8.1 and the shell and ISE on Win10 it works fine. This wouldn't be the first time that my particular Win8.1 install is goofy... :-/ Thanks for the golf!

– AdmBorkBork – 2016-12-10T05:49:50.547

Also did this not work for all test cases? $args|%{@($args|sort -d).indexof($_)+1} it is shorter but I have not had a good look to know if it works – Matt – 2016-12-10T05:53:56.807

@Matt That doesn't work because the second $args functions as input for the script block of the loop {...}, just like if you were using a filter or function. – AdmBorkBork – 2016-12-10T06:14:31.563

3

Octave, 15 bytes

@(x)sum(x<x')+1

Port of my MATL answer to Octave. It also works in Matlab R2016b.

The code defines an anonymous function. To call it, assign it to a variable. Try it at Ideone.

Luis Mendo

Posted 2016-12-08T19:12:07.663

Reputation: 87 464

3

JavaScript (ES6), 38 36 bytes

a=>a.map(e=>a.map(d=>r+=e<d,r=1)&&r)

Edit: Saved 2 bytes thanks to @ETHproductions.

Neil

Posted 2016-12-08T19:12:07.663

Reputation: 95 035

.map FTW ;-) a=>a.map(e=>a.map(d=>r+=e<d,r=1)&&r) – ETHproductions – 2016-12-08T23:09:41.803

3@ETHproductions Why do you always have to spoil my fun? – Neil – 2016-12-09T00:22:42.927

2

Jelly, 5 bytes

<S‘ð€

TryItOnline!

How?

<S‘ð€ - Main link: listOfValues
   ð  - dyadic chain separation
    € - for each
<     - less than (vectorises) - yields a list of 1s and 0s
 S    - sum - yields number of values the current value is less than (those that beat it)
  ‘   - increment - the place of a value is the number that beat it plus 1.

Jonathan Allan

Posted 2016-12-08T19:12:07.663

Reputation: 67 804

How similar is this to the J code I was about to submit? 1+(+/@:<)"0 1~ – Dane – 2016-12-08T21:28:39.803

Looks similar (uses a reduce to sum?), but that should by no means stop you posting your code! – Jonathan Allan – 2016-12-08T21:34:26.663

I guess I was more wondering what "dyadic chain separation" and "for each" do in a J-inspired language. – Dane – 2016-12-08T21:44:50.867

Ah, well from your explanation I think your code is more like >€µS‘, or really like <@€µS‘ (@ reverses arguments to the < operator). The J ~ is implicit in the chain to the left of the µ, which is monadic (rather than dyadic) separation and < vectorises if the argument(s) is(are) list(s). – Jonathan Allan – 2016-12-08T22:10:57.190

2

Perl 6,  42  26 bytes

Find the first index :k in a reversed [R,] sorted list

{map {[R,](.sort).first(*==$^a,:k)+1},@$_}

Count the values that are larger, and add one

{map {1+.grep(*>$^a)},@$_}

Brad Gilbert b2gills

Posted 2016-12-08T19:12:07.663

Reputation: 12 713

2

JavaScript, 87 49 bytes

f=a=>a.slice().map(function(v){return a.sort(function(a,b){return b-a}).indexOf(v)+1 })

a=>[...a].map(v=>a.sort((a,b)=>b-a).indexOf(v)+1)

Thanks Conor O'Brien and ETHproductions!

Oliver

Posted 2016-12-08T19:12:07.663

Reputation: 7 160

1You can use an anonymous function in the map, i.e. v=>a.sort((a,b)=>b-a).indexOf(v)+1. – Conor O'Brien – 2016-12-08T19:55:31.937

You don't need .slice() at all, because .map operates on a copy of the array. – ETHproductions – 2016-12-08T20:12:19.830

And our site policy is that the function does not need to be named, so you can remove the leading f=, too. – Conor O'Brien – 2016-12-08T20:14:00.303

@ETHproductions If I remove slice, passing in [18,13,18] returns [1,1,2] instead of [1, 3, 1] – Oliver – 2016-12-08T20:16:45.433

Oh, that's weird... I guess it's because a.sort() stores the sorted array in a. But you can change a.slice() to [...a] to save a few bytes. – ETHproductions – 2016-12-08T20:20:55.123

Thanks again @ETHproductions. On an unrelated note, if I have a function f=(n,t)=>s=n.split('.'), can I call s[1] inside of that function? n would look like '1.2.3' – Oliver – 2016-12-08T20:27:59.110

@ETHproductions My idea is to do something like f=(n,t)=>s=n.split('.');s[t]++ – Oliver – 2016-12-08T20:41:48.853

Yes, you can do that, but you'll need to wrap multiple statements in parentheses or braces: f=(n,t)=>{s=n.split('.');s[t]++} or f=(n,t)=>(s=n.split('.'),s[t]++) – ETHproductions – 2016-12-08T23:07:56.387

2

J, 14 8 bytes

1+1#.</~

How?

1+1#.</~ - Consumes and returns a list of integers
       ~ - Use the same list for both inputs
     </  - Create a table of less-than comparisons
  1#.    - Treat each row like digits of a base-one number, returning a list of integers
1+       - Increment the results

Previous solution

1+(+/@:<)"0 1~

Dane

Posted 2016-12-08T19:12:07.663

Reputation: 291

Hello, I've found a shorter version for 8 bytes 1+1#.</~. Row-wise summation is performed using base 1 conversion. Another alternative is 1+\:~i.] which is also 8 bytes. – miles – 2016-12-08T22:07:45.180

Nice! Do you want to post your own answer? I'll otherwise include the base-one improvement. – Dane – 2016-12-08T22:36:08.373

2Nah, I'm fine with just suggesting byte-savings. Feel free to use them – miles – 2016-12-08T23:58:13.803

2

Mathematica, 44 bytes 42 bytes 40 bytes

xPosition[SortBy[x,-#&],#][[1,1]]&/@x

is the 3 byte private use character U+F4A1 (Wolfram docs page)

Edit: Thanks to JHM for the byte savings.

ngenisis

Posted 2016-12-08T19:12:07.663

Reputation: 4 600

1Fails for test case {10,2,5,4,15,5} (the output should be {2,6,3,5,1,3} not {2,5,3,4,1,3}. Note that 4 has to be skipped because there are two 5s in the input). – JungHwan Min – 2016-12-08T23:22:38.487

Duly corrected. – ngenisis – 2016-12-08T23:58:14.933

1-2 bytes by switching x and # (effectively getting rid of the parentheses): xPosition[SortBy[x,-#&],#][[1,1]]&/@x. – JungHwan Min – 2016-12-09T00:00:05.707

2

Pyke, 6 bytes

FQS_@h

Try it here!

F      - for i in input():
 QS    -     sorted(input())
   _   -    reversed(^)
    @  -   i.find(^)
     h -  ^+1 (not required if allowed to start from 0)

Blue

Posted 2016-12-08T19:12:07.663

Reputation: 26 661

1

Haskell, 28 bytes

f l=[1+sum[1|y<-l,y>x]|x<-l]

Just some list comprehensions.

xnor

Posted 2016-12-08T19:12:07.663

Reputation: 115 687

20sec too late. I was about to post the very same answer. – nimi – 2016-12-08T19:36:11.987

2

@nimi You can post it too!

– xnor – 2016-12-08T19:36:52.437

1

Wonder, 28 bytes

@(->@+1:0iO#0rev sort#I#1)#0

Usage:

(@(->@+1:0iO#0rev sort#I#1)#0)[6 2 9 7 2 6 5 3 3 4]

Map over input array with a function that adds 1 to the first index of the item in a descending-sorted version of the input.

Mama Fun Roll

Posted 2016-12-08T19:12:07.663

Reputation: 7 234

1

Dyalog APL, 7 bytes

⊢⍳⍨⍒⊃¨⊂

arguments'

⍳⍨ indices in

the indices which would sort the argument descending

⊃¨ each picked from

the entire argument

TryAPL online!

Adám

Posted 2016-12-08T19:12:07.663

Reputation: 37 779

1

Mathematica, 37 bytes

Min@Position[-Sort@-#,i]~Table~{i,#}&

A pure function which will rank it's input, as per the rules of the problem. Ex:

Min@Position[-Sort@-#, i]~Table~{i, #} &[{6, 2, 9, 7, 2, 6, 5, 3, 3, 4}]
(*{3, 9, 1, 2, 9, 3, 5, 7, 7, 6}*)

J. Antonio Perez

Posted 2016-12-08T19:12:07.663

Reputation: 1 480

1

Jellyfish, 15 bytes

p`&& ~i
  >/+`<

Try it online!

Explanation

There doesn't seem to be a good way to find the index of a value in a list in Jellyfish yet, so this uses the approach of counting how many values are bigger than current one and incrementing the result. This is largely done by constructing a unary function which computes this value for a given element.

     `<

This creates a threaded version of the comparison operator, so if you give this an integer and a list, it will return a list of comparison results between that integer and each element in the list.

     ~i
     `<

This curries the right-hand argument of the previous function with the input list. So the result is a unary function which takes an integer and gives you the list of comparison results with the input of the program.

   & ~i
   /+`<

Here, /+ is reduction by addition, which means it's simply a "sum this list" function. & composes this onto the previous function, so we now have a unary function which counts how many values in the input are bigger than that integer.

  && ~i
  >/+`<

We also compose the increment function onto this.

 `&& ~i
  >/+`<

Finally, we thread this function as well, so that it's automatically applied to each integer of a list passed to it. Due to the layout of the code, i happens to be taken as the input of this function as well, so that this computes the desired output.

p`&& ~i
  >/+`<

Finally, this prints the result.

Martin Ender

Posted 2016-12-08T19:12:07.663

Reputation: 184 808

1

brainfuck, 124 bytes

->,[>>>+>,]<[-<+]+[-->[<[<<<<]>>>+>[>[>>]<[[<<+<<]>+>[->>>>]]<+>>>]+[-<<+]->]<[<
<<<]>+.,>>[>[>->+>>]<<[-<<<<]>-]+[->+]+>>>>]

Formatted:

->
,[>>>+>,]
<[-<+]
+
[
  -->
  [
    <[<<<<]
    >>>+>
    [
      >[>>]
      <
      [
        [<<+<<]
        >+>[->>>>]
      ]
      <+> >>
    ]
    +[-<<+]
    ->
  ]
  <[<<<<]
  >+.,>>
  [
    >[>->+>>]
    <<[-<<<<]
    >-
  ]
  +[->+]
  +>>>>
]

This is designed for 8-bit brainfuck implementations. Input and output are via byte values.

Try it online.

For each element, this counts the number of elements greater than it, then prints the result plus one. This is accomplished by incrementing all elements until the current element equals zero, updating the result whenever another element becomes zero before the current element.

The tape is broken into 4-cell nodes,

b c 0 0

where c is the element and b is a navigation flag that is negative one for the current element, otherwise one.

The result and a copy of the current element are kept to the left of the array.

Mitch Schwartz

Posted 2016-12-08T19:12:07.663

Reputation: 4 899

1

Java, 215 bytes

public class G{public static void L(int[]A){int[]r=new int[A.length];for(int i=0;i<A.length;i++){int c=1;for(int j=0;j<A.length;j++){if(A[j]>A[i])c++;}r[i]=c;}for(int i=0;i<r.length;i++)System.out.print(r[i]+",");}}

Explanation:

Very self explanatory.

Basically for each integer in the array it checks how many are larger than it, then prints the new array with the rankings.

I'm sorry this isn't very concise but it's my first try at one of these and I didn't see an entry for java. I'm sure it can be golfed down more.

It can be run just by making reference to the static method and passing an array. I didn't think it was necessary to write the main function but if it is I'll do that in the future.

Henry

Posted 2016-12-08T19:12:07.663

Reputation: 11

Can you remove some of this whitespace? As it is this isn't golfed really at all. (i.e. the spaces in r = new) – Rɪᴋᴇʀ – 2016-12-28T23:06:12.130

@EasterlyIrk Yes, sorry i'm not used to doing this. I think I got rid of all unnecesary whitespace. – Henry – 2016-12-28T23:46:07.893

Can you name the "rankNumbersGolf" something shorter like "G" or something? – Rɪᴋᴇʀ – 2016-12-28T23:47:23.283

@EasterlyIrk Yes, thanks. – Henry – 2016-12-28T23:56:55.920

I don't java well, but can you remove some spaces in the three for (? – Rɪᴋᴇʀ – 2016-12-28T23:58:03.597

@EasterlyIrk Wow, yes I can. So used to coding for clarity that I never think to do things like that. – Henry – 2016-12-29T00:00:48.277

0

Ruby, 45 40 bytes

->a{a.map{|x|a.sort.reverse.index(x)+1}}

Lee W

Posted 2016-12-08T19:12:07.663

Reputation: 521

How is this called? I cannot get it to match the test cases, there seems to be a bug with equal ranks. For example [10, 2, 5, 4, 15, 5] gives me output [2, 5, 3, 4, 1, 3] when it should be [2, 6, 3, 5, 1, 3] - I think to fix that you just remove the .uniq - saving 5 bytes! – Neil Slater – 2016-12-09T13:18:46.233

I seem to have misread the question. Thanks for spotting that! – Lee W – 2016-12-09T16:37:11.817

0

PHP, 101 bytes

There must be some shorter way.

function f(&$a){for($r=1;$v++<max($a);$r+=$n,$n=0)foreach($a as$k=>$w)if($w===$v){$a[$k]="$r";$n++;}}

function takes input as array of integers, overwrites input variable with ranks as numeric strings.

Usage: $a=[1,2,4,2,2,3];f($a);print_r($a);

Titus

Posted 2016-12-08T19:12:07.663

Reputation: 13 814

0

Clojure, 48 44 bytes

Update: using for instead of map

#(for[i %](+(count(filter(partial < i)%))1))

Simply filters each value smaller than the current one, counts the length of the list and increments by one.

NikoNyrh

Posted 2016-12-08T19:12:07.663

Reputation: 2 361

0

Tcl, 54 bytes

proc R L {lmap x $L {lsearch .\ [lsort -r -de $L] $x}}

Try it online!

sergiol

Posted 2016-12-08T19:12:07.663

Reputation: 3 055

0

PHP, 84 bytes

function r($l){$s=$l;rsort($s);foreach($l as$n)$r[]=array_search($n,$s)+1;return$r;}

Usage: Pass the function r your array of integers and it will return the corresponding array of ranked integers.

Passing tests here.

Progrock

Posted 2016-12-08T19:12:07.663

Reputation: 131

0

Perl 5, 23 +2 (-ap)

s/\d+/1+grep$&<$_,@F/ge

Try it online

Nahuel Fouilleul

Posted 2016-12-08T19:12:07.663

Reputation: 5 582

0

K (oK), 11 bytes

Solution:

1+(x@>x)?x:

Try it online!

Examples:

1+(x@>x)?x:6 2 9 7 2 6 5 3 3 4
3 9 1 2 9 3 5 7 7 6
1+(x@>x)?x:5 6 14 19 13 5 19 9 19 9 9 19
11 10 5 1 6 11 1 7 1 7 7 1

Explanation:

Lookup position of original list in sorted list, then add one.

1+(x@>x)?x: / the solution
         x: / save input as x
  (  >x)    / return indices of x sorted in descending order
   x@       / apply these indices to x (thus sort x)
        ?   / lookup right in left
1+          / add one

streetster

Posted 2016-12-08T19:12:07.663

Reputation: 3 635