More strings and arrays
Weekly challenge 322 — 19 May 2025
Week 322: 19 May 2025
You are given an array of integers. Write a script to return an array of the ranks of each element: the lowest value has rank 1, next lowest rank 2, etc. If two elements are the same then they share the same rank.
Example 1 Input: @ints = (55, 22, 44, 33) Output: (4, 1, 3, 2) Example 2 Input: @ints = (10, 10, 10) Output: (1, 1, 1) Example 3 Input: @ints = (5, 1, 1, 4, 3) Output: (4, 1, 1, 3, 2)
My algorithm is as follows:
Create a hash %numbers
with the numbers from the input array as the keys. This automatically eliminates duplicates.
Create an array @rank
like this:
$rank[$_] = $j ++ for sort {$a <=> $b} keys %numbers;
which creates an array @rank
such that the rank of value $array[$i]
is $rank[$i]
- for
example, the rank of the lowest unique value in the input array is
1, the next lowest 2 and so on.
Create the desired output array, @ranking
, by setting:
$ranking[$_] = $rank[$array[$_]] for 0 .. $#array;
which creates the desired output array, @ranking
where $ranking[$i]
contains the rank of element $i
in the input array.
This works for any input array values that are positive, but the
challenge states 'integers' rather than 'positive integers'.
To cope with that, I first determine the minimum value $min
in @array
and then offset the indices of @rank
by $min
so that they
are never negative.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2025-05-19 use utf8; # Week 322 - task 2 - Rank array use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; use Encode; use List::Util 'min'; rank_array(55, 22, 44, 33); rank_array(10, 10, 10); rank_array(5, 1, 1, 4, 3); rank_array(0); rank_array(-3, -3, -3, -2, -2, -1, 0); # bigger example my @array; push @array, int(rand(100)) for 0 .. 25; rank_array(@array); sub rank_array { my (@array, @rank, @ranking, $n, $j, %numbers, $min); # initialise @array = @_; # to cope with -ve numbers $min = min(@array); # make # with keys of unique numbers $numbers{$_} = 1 for @array; # rank the numbers smallest to largest $j = 1; $rank[$_ - $min] = $j ++ for sort {$a <=> $b} keys %numbers; # assign the ranks to @ranking in the original order $ranking[$_] = $rank[$array[$_] - $min] for 0 .. $#array; say qq[\nInput: (] . join(', ', @array) . q[)]; say qq[Output: (] . join(', ', @ranking) . q[)]; }
Input: (55, 22, 44, 33) Output: (4, 1, 3, 2) Input: (10, 10, 10) Output: (1, 1, 1) Input: (5, 1, 1, 4, 3) Output: (4, 1, 1, 3, 2) Input: (0) Output: (1) Input: (-3, -3, -3, -2, -2, -1, 0) Output: (1, 1, 1, 2, 2, 3, 4) Input: (8, 57, 77, 28, 10, 65, 28, 3, 67, 68, 24, 84, 52, 80, 64, 66, 80, 81, 95, 53, 47, 83, 57, 81, 86, 11) Output: (2, 10, 16, 6, 3, 12, 6, 1, 14, 15, 5, 20, 8, 17, 11, 13, 17, 18, 22, 9, 7, 19, 10, 18, 21, 4)
Any content of this website which has been created by Peter Campbell Smith is in the public domain