Mark Tomlin
Mark Tomlin

Reputation: 8943

Sorting Arrays by More the One Value, and Prioritizing the Sort based on Column data

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&ps=1&idk=35cP2S05Cvj3z7564aXKyw0Mqf1Hhx7P&s=2&action=pb&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);

?>

Upvotes: 0

Views: 233

Answers (2)

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 799062

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);

Upvotes: 2

goat
goat

Reputation: 31823

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;
});

Upvotes: 1

Related Questions