Adam L.
Adam L.

Reputation: 187

How to assign a rank number to an array

I have an array of numbers, for example, myarray = (45,3,56,7,21). What I need to be able to do is rank the values into another array so for the above I would end up with myarray2 = (4,1,5,2,3).

Many thanks,

Adam

Upvotes: 3

Views: 3387

Answers (6)

Artefacto
Artefacto

Reputation: 97835

Well, you could do something like:

$b = $a = array(45,3,56,7,21);
sort($b);
$r = array_map(
    function ($number) use ($b) {
        return array_search($number, $b) + 1;
    }, $a);

But to make it efficient, you must implement your own sorting function. Here's a Java implementation I couldn't bother to translate (from weka):

/**
 * Sorts a given array of integers in ascending order and returns an 
 * array of integers with the positions of the elements of the original 
 * array in the sorted array. The sort is stable. (Equal elements remain
 * in their original order.)
 *
 * @param array this array is not changed by the method!
 * @return an array of integers with the positions in the sorted
 * array.
 */
public static int[] sort(int[] array) {

    int[] index = new int[array.length];
    int[] newIndex = new int[array.length];
    int[] helpIndex;
    int numEqual;

    for (int i = 0; i < index.length; i++) {
        index[i] = i;
    }
    quickSort(array, index, 0, array.length - 1);

    // Make sort stable
    int i = 0;
    while (i < index.length) {
        numEqual = 1;
        for (int j = i + 1; ((j < index.length)
                && (array[index[i]] == array[index[j]]));
                j++) {
            numEqual++;
        }
        if (numEqual > 1) {
            helpIndex = new int[numEqual];
            for (int j = 0; j < numEqual; j++) {
                helpIndex[j] = i + j;
            }
            quickSort(index, helpIndex, 0, numEqual - 1);
            for (int j = 0; j < numEqual; j++) {
                newIndex[i + j] = index[helpIndex[j]];
            }
            i += numEqual;
        } else {
            newIndex[i] = index[i];
            i++;
        }
    }
    return newIndex;
}

private static void quickSort(int[] array, int[] index,
        int left, int right) {

    if (left < right) {
        int middle = partition(array, index, left, right);
        quickSort(array, index, left, middle);
        quickSort(array, index, middle + 1, right);
    }
}

Upvotes: 1

Zak
Zak

Reputation: 25205

Pretty straightforward if you use a sorting function that maintains the original keys like asort:

Also, since this uses the internal php sorting, the execution time for the sort is n log(n) I believe

$myArray = (45,3,56,7,21);
$myArrayCopy = $myArray;
//asort will sort an array while preserving the key value
asort($myArrayCopy);

foreach($myArraycopy as $key => $value)
{
    //map the keys of the array to the original index locations
    $sortIndexArray[] =  $key;
}

Upvotes: 0

shamittomar
shamittomar

Reputation: 46692

There you go, complete solution:

<?php

$myarray = array(45,3,56,7,21);

//create a copy and sort
$myarray_copy = $myarray;
sort($myarray_copy);

//reverses key and values
$myarray_copy = array_flip($myarray_copy);

//create result by using keys from sorted values + 1
foreach($myarray as $val)
    $myarray2[] = $myarray_copy[$val]+1;

//print final array
print_r($myarray2);

/*
Output:

Array ( [0] => 4 [1] => 1 [2] => 5 [3] => 2 [4] => 3 )
*/
?>

Upvotes: 2

jigfox
jigfox

Reputation: 18185

Here is a function to do this:

function get_array_ranking($array){
  $ranking = array();
  foreach ($array as $number) {
    $smaller = 1;
    foreach ($array as $number2) {
      if ($number2 < $number) $smaller++;
    }
    $ranking[] = $smaller;
  }
  return $ranking;
}

Upvotes: 0

Razor Storm
Razor Storm

Reputation: 12336

Very interesting.

What I can come up with on the spot is something like this:

Sort the array and put that into another array, then fill out myarray2 by searching the intermediate array for the value, and then filling out myarray2's values with the index.

$myarraytemp = sort clone $myarray;

foreach ($myarray as $num)
{
    array_push($myarray2, array_search($num,$myarraytemp));
}

Alternatively you can do this:

foreach ($myarray as $num)
{
    $rank=0;
    foreach ($myarray as $innernum)
    {
        if($innernum<= $num)
            $rank++;             
    }
    array_push($myarray2, $rank);
}

Upvotes: 1

Ishtar
Ishtar

Reputation: 11662

Take a number of your array, count how many numbers are smaller than that one, add one and you have the rank.

Upvotes: 0

Related Questions