Reputation: 187
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
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
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
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
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
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
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