I have a PHP array (retrieved from a DB) of employees calculated data. There are about 10 columns per employee, 8 of them numerical (the other 2 are id and name). Here's a short sample:
David: 1024, 75, 22 Mike: 500, 100, 25 Jeff: 700, 82, 10
I can easily sort the array on any of the (numerical) fields to show who's at the top/bottom, but what I'd really like to show in the final table view is ranking by the value, so people won't have to sort and re-sort the table to get what they want. Here's an example of the table sorted by the first column, showing rankings in parentheses:
David: 1024 (#1), 75 (#3), 22 (#2) Jeff: 700 (#2), 82 (#2), 10 (#3) Mike: 500 (#3), 100 (#1), 25 (#1)
Now, I know the easiest approach is just to sort the table by column, use the row indexes as the ranking and repeat per every column. I just wondered if I could find a more efficient way.
I thought about using ordered queues (one per column that needs ranking), scanning the array once and pushing values into the queues. But:
Could anyone please suggest the best approach, and/or confirm I should just re-sort the array several times?
Thanks for your time!
Ok, after much deliberation, I decided to go the "sort every column" route. For future reference by anyone interested, here's the function I've added to my class - it's called once per every column I need ranked:
private function calculateRankings(&$employees, $columnName) {
$comparer = "return (\$a[$columnName][0] == \$b[$columnName][0]) ? 0 : (\$a[$columnName][0] > \$b[$columnName][0] ? -1 : 1);";
usort($employees, create_function('$a,$b', $comparer));
foreach($employees as $key => &$employee) {
$employee[$columnName][1] = $key + 1;
}
}
The +1 is due to the keys being zero-based.
You prepare for this function by turning each field you need ranked into a 2-element array: the first ([0]) contains the value, and the second ([1]) will contain the rank in the end.
I.e.: $employees['salary'] = array(1550, 0);
. You then call the function like this:$this->calculateRankings($employees, 'salary');
.
I sincerely hope this helps someone, someday. Thanks to all responders/commenters!
UPDATE 4/9: The function I supplied before couldn't work - there's no way to pass a third parameter (in our case, the column name) into the comparer function. The only way to do it is to use a static class variable, or a create_function hack that I ended up with. Sorry for any confusion.
I'm afraid you would have to stick with the initial approach.
There is no escape from having to iterate through all the columns and compute the ranking information for each individual one.
What you could do is optimize the algorithm to accomplish that task more efficiently.
PS.: I don't think that the algorithm is unusual enough for you to worry about complexity, order of growth or running time, even though performance is always important.