使用usort()提升元素

I have a simple array that looks like this:

array (size=6)
  0 => 
    array (size=2)
      'id' => int 1
      'primary' => boolean false
  1 => 
    array (size=2)
      'id' => int 2
      'primary' => boolean false
  2 => 
    array (size=2)
      'id' => int 3
      'primary' => boolean false
  3 => 
    array (size=2)
      'id' => int 4
      'primary' => boolean true
  4 => 
    array (size=2)
      'id' => int 5
      'primary' => boolean false
  5 => 
    array (size=2)
      'id' => int 6
      'primary' => boolean false

When the array is generated, it is always ordered by id, like the above. What I wish to do is to have usort() promote the array element where primary is TRUE to be the first element. There will always only be one element where primary is TRUE.

I then wrote a simple comparison function to use with usort():

$data = array(
            array('id' => 1, 'primary' => FALSE),
            array('id' => 2, 'primary' => FALSE),
            array('id' => 3, 'primary' => FALSE),
            array('id' => 4, 'primary' => TRUE),
            array('id' => 5, 'primary' => FALSE),
            array('id' => 6, 'primary' => FALSE),
        );

function sortArray($a, $b){

    if($a['primary']){
        return -1;
    }elseif($b['primary']){
        return 1;
    }else{
        return 0;
    }
}

var_dump($data);

usort($data, 'sortArray');

var_dump($data);

While the element with primary = TRUE is now promoted to the front, the rest of the elements are now sorted in reverse order and the element with id = 5 is out of place:

array (size=6)
  0 => 
    array (size=2)
      'id' => int 4
      'primary' => boolean true
  1 => 
    array (size=2)
      'id' => int 5
      'primary' => boolean false
  2 => 
    array (size=2)
      'id' => int 6
      'primary' => boolean false
  3 => 
    array (size=2)
      'id' => int 3
      'primary' => boolean false
  4 => 
    array (size=2)
      'id' => int 2
      'primary' => boolean false
  5 => 
    array (size=2)
      'id' => int 1
      'primary' => boolean false

I know I can compare the ids, if both elements have the primary property as false:

function sortArray($a, $b){

    if($a['primary']){
        return -1;
    }elseif($b['primary']){
        return 1;
    }else{
        return $a['id'] > $b['id'];
    }
}

But, why is usort randomizing the order of my other elements? Is it possible to use usort() to just promote elements and leave the rest of the array untouched?

Try this comparison function:

function sortArray($a, $b)
{
    if($a['primary'])
    {
        $result = 1;
    }
    elseif($b['primary'])
    {
        $result = -1;
    }
    else
    {
        $result = ($a['id'] < $b['id']) ? -1 : 1;
    }

    return $result;
}

You can change $result = ($a['id'] < $b['id']) ? -1 : 1; to $result = ($a['id'] < $b['id']) ? 1 : -1; to sort in reverse order.

In your comparison function, return $a['id'] > $b['id'] will either return 0 or 1 (true or false), never -1. From the documentation:

"The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second."

The fastest comparison sort is O(N*log(N)), which is slower than linear time. For this reason, I recommend just iterating over the array (O(N), linear time) and moving the element with 'primary' set to true to the front of the array.

usort() will reindex keys. Try using uasort() instead.