1

I have the following array

$q = array(
  array(
    'ID'=>'0',
    'post_date'=>'2014-09-20 20:01:52',
    'post_type'=>'event_type'
  ),
  array(
    'ID'=>'1',
    'post_date'=>'2014-09-13 11:33:10',
    'post_type'=>'post'
  ),
  array(
    'ID'=>'2',
    'post_date'=>'2014-09-11 16:55:32',
    'post_type'=>'cameras'
  ),
  array(
    'ID'=>'3',
    'post_date'=>'2014-09-10 17:44:52',
    'post_type'=>'post'
  ),
    array(
    'ID'=>'4',
    'post_date'=>'2014-09-09 17:44:52',
    'post_type'=>'cameras'
  ),

  array(
    'ID'=>'5',
    'post_date'=>'2014-09-07 15:20:10',
    'post_type'=>'post'
  ),
  array(
    'ID'=>'6',
    'post_date'=>'2014-07-08 20:01:52',
    'post_type'=>'event_type'
  ),
  array(
    'ID'=>'7',
    'post_date'=>'2014-07-06 15:26:28',
    'post_type'=>'cameras'
  ),
  array(
    'ID'=>'8',
    'post_date'=>'2014-06-30 17:44:52',
    'post_type'=>'event_type'
  ),
);

I need to sort this by post_type in the order that I specify. The order should be event_type, then post and then cameras. I can achieve that, no problem, with the following code

function cmp($a, $b)
{
        if($b['post_type'] == 'event_type') {
            return 1;
        }
        elseif($a['post_type'] == 'event_type') {
            return -1;
        }
        elseif($b['post_type'] == 'post') {
            return 1;
        }
        elseif($a['post_type'] == 'post') {
            return -1;
        }
        elseif($b['post_type'] == 'cameras') {
            return 1;
        }
        elseif($a['post_type'] == 'cameras') {
            return -1;
        }
        return ($a < $b) ? -1 : 1;
}


usort($q, "cmp");

The array is correctly sorted by post_type as I specified. Where I get the problem is, this sorting does not keep the array sorted by ID. Let me explain. Here is the output after sorting

array(9) {
  [0]=>
  array(3) {
    ["ID"]=>
    string(1) "8"
    ["post_date"]=>
    string(19) "2014-06-30 17:44:52"
    ["post_type"]=>
    string(10) "event_type"
  }
  [1]=>
  array(3) {
    ["ID"]=>
    string(1) "0"
    ["post_date"]=>
    string(19) "2014-09-20 20:01:52"
    ["post_type"]=>
    string(10) "event_type"
  }
  [2]=>
  array(3) {
    ["ID"]=>
    string(1) "6"
    ["post_date"]=>
    string(19) "2014-07-08 20:01:52"
    ["post_type"]=>
    string(10) "event_type"
  }
  [3]=>
  array(3) {
    ["ID"]=>
    string(1) "1"
    ["post_date"]=>
    string(19) "2014-09-13 11:33:10"
    ["post_type"]=>
    string(4) "post"
  }
  [4]=>
  array(3) {
    ["ID"]=>
    string(1) "3"
    ["post_date"]=>
    string(19) "2014-09-10 17:44:52"
    ["post_type"]=>
    string(4) "post"
  }
  [5]=>
  array(3) {
    ["ID"]=>
    string(1) "5"
    ["post_date"]=>
    string(19) "2014-09-07 15:20:10"
    ["post_type"]=>
    string(4) "post"
  }
  [6]=>
  array(3) {
    ["ID"]=>
    string(1) "2"
    ["post_date"]=>
    string(19) "2014-09-11 16:55:32"
    ["post_type"]=>
    string(7) "cameras"
  }
  [7]=>
  array(3) {
    ["ID"]=>
    string(1) "7"
    ["post_date"]=>
    string(19) "2014-07-06 15:26:28"
    ["post_type"]=>
    string(7) "cameras"
  }
  [8]=>
  array(3) {
    ["ID"]=>
    string(1) "4"
    ["post_date"]=>
    string(19) "2014-09-09 17:44:52"
    ["post_type"]=>
    string(7) "cameras"
  }
}

Look at, for example, how event_type is sorted. It sorts the ID in the following order8, 0, 6. I need it to be 0, 6, 8. The same for cameras. After ordering, the ID order is 2, 7, 4 where as I need it 2, 4, 7

Any suggestions on how to solve this? Am I using usort correctly?

Pieter Goosen
  • 9,768
  • 5
  • 35
  • 55

1 Answers1

3

You should always compare TWO things inside the callback method. You are basically saying "this is greater" as soon as you hit a certain value on ONE element:

if($b['post_type'] == 'event_type') {
   return 1;
}

what if both are event_type? You are ignoring that.

You should do it more like this:

function cmp($a, $b)
{
   $types = array (
    'event_type' => 1,
    'post' => 2,
    'cameras' => 3
   );

   $compare1 = $types[$a["post_type"]] - $types[$b["post_type"]];

   if ($compare1 === 0){
     //same category, compare by id.
     return $a["ID"] - $b["ID"];
   }else{
     //different category, save to ignore the id.
     return $compare1;
   }
}

ps.: Play around if it should be $a-$b or $b-$a - I always mess up on that.

dognose
  • 20,360
  • 9
  • 61
  • 107