views:

41

answers:

2

I'm looking for a way to sort an array, based on the information in each row, based on the information in certain cells, that I'll call columns.

Each row has columns that must be sorted based on the priority of: timetime, lapcount & timestamp.

Each column cotains this information: split1, split2, split3, laptime, lapcount, timestamp.

laptime if in hundredths of a second. (1:23.45 or 1 Minute, 23 Seconds & 45 Hundredths is 8345.) Lapcount is a simple unsigned tiny int, or unsigned char. timestamp is unix epoch.

The lowest laptime should be at the get a better standing in this sort. Should two peoples laptimes equal, then timestamp will be used to give the better standing in this sort. Should two peoples timestamp equal, then the person with less of a lapcount get's the better standing in this sort.

By better standing, I mean closer to the top of the array, closer to the index of zero where it a numerical array.

I think the array sorting functions built into php can do this with a callback, I was wondering what the best approch was for a weighted sort like this would be.

<?php

    $racers = array('Dygear', 'filur', 'glyphon', 'AndroidXP', 'HorsePower', 'Becky Rose', 'kanutron', 'Victor');

    foreach ($racers as $racer)
        $query[$racer] = unserialize(file_get_contents('http://lfsworld.net/pubstat/get_stat2.php?version=1.4&amp;ps=1&amp;idk=35cP2S05Cvj3z7564aXKyw0Mqf1Hhx7P&amp;s=2&amp;action=pb&amp;racer='.urlencode($racer)));

    foreach ($query as $racer => $data)
    {
        foreach ($data as $row)
        {
            if ($row['track'] == '000' && $row['car'] == 'FOX')
                $sortArray[$racer] = $row;
        }
    }

    # Sort the Array $sortArray

    var_dump($sortArray);

?>
+2  A: 

What you want is a Schwartzian transform. Create a new array with the values to sort by as the key and the original values as the values, sort the array by key, then strip away the keys.

EDIT:

Quick-and-dirty implementation:

$times = Array(
  Array('val1' => 1, 'val2' => 3, 'val3' => 8),
  Array('val1' => 1, 'val2' => 2, 'val3' => 5),
  Array('val1' => 3, 'val2' => 8, 'val3' => 6),
  Array('val1' => 2, 'val2' => 2, 'val3' => 1),
  Array('val1' => 4, 'val2' => 7, 'val3' => 3)
);

$timesdec = Array();
foreach($times as $time)
{
  $timesdec[sprintf('%010d%010d', $time['val1'], $time['val3'])] = $time;
}

ksort($timesdec);
$newtimes = array_values($timesdec);
var_dump($newtimes);
Ignacio Vazquez-Abrams
Hoping for an example implementation. Because, I can't quite get my head around this one.
Mark Tomlin
So in essence, what you are doing is CONCATing the numbers together in the hopes that the smallest value will be the most correct. Intresting.
Mark Tomlin
Subtracting from a sufficiently-large constant will allow you do sort in descending order instead.
Ignacio Vazquez-Abrams
+1  A: 

This is untested, and I felt like using php 5.3. But, you can do the same without anonymous functions. You don't really need to use separate functions for each of the column comparisons like I did. But, it seems like you're really trying to replicate the way a database sorts multiple columns, so I'm giving you something close to it.

$comparatorSequence = array(
    function($a, $b) {
        return $a['laptime'] - $b['laptime'];
    }
  , function($a, $b) {
        return $a['timestamp'] - $b['timestamp'];
    }
  , function($a, $b) {
        return $a['lapcount'] - $b['lapcount'];
    }
);

usort($theArray, function($a, $b) use ($comparatorSequence) {
    foreach ($comparatorSequence as $cmpFn) {
        $diff = call_user_func($cmpFn, $a, $b);
        if ($diff !== 0) {
            return $diff;
        }
    }
    return 0;
});
chris
An interesting solution. Thank you for the post.
Mark Tomlin