Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a php array of arrays by custom order

I have an array of arrays:

Array (      [0] => Array (         [id] = 7867867,         [title] = 'Some Title'),     [1] => Array (         [id] = 3452342,         [title] = 'Some Title'),     [2] => Array (         [id] = 1231233,         [title] = 'Some Title'),     [3] => Array (         [id] = 5867867,         [title] = 'Some Title') ) 

The need to go in a specific order:

  1. 3452342
  2. 5867867
  3. 7867867
  4. 1231233

How would I go about doing that? I have sorted arrays before, and read plenty of other posts about it, but they are always comparison based (i.e. valueA < valueB).

Help is appreciated.

like image 628
Honus Wagner Avatar asked Jun 21 '12 19:06

Honus Wagner


People also ask

How can I sort an array in PHP without sort method?

php function sortArray() { $inputArray = array(8, 2, 7, 4, 5); $outArray = array(); for($x=1; $x<=100; $x++) { if (in_array($x, $inputArray)) { array_push($outArray, $x); } } return $outArray; } $sortArray = sortArray(); foreach ($sortArray as $value) { echo $value . "<br />"; } ?>

How do you sort an array of associative arrays by the value of a given key in PHP?

The arsort() function sorts an associative array in descending order, according to the value. Tip: Use the asort() function to sort an associative array in ascending order, according to the value. Tip: Use the krsort() function to sort an associative array in descending order, according to the key.


2 Answers

You can use usort() to dictate precisely how the array is to be sorted. In this case, the $order array can be used within the comparison function.

The example below uses a closure to make life easier.

$order = array(3452342, 5867867, 7867867, 1231233); $array = array(     array('id' => 7867867, 'title' => 'Some Title'),     array('id' => 3452342, 'title' => 'Some Title'),     array('id' => 1231233, 'title' => 'Some Title'),     array('id' => 5867867, 'title' => 'Some Title'), );  usort($array, function ($a, $b) use ($order) {     $pos_a = array_search($a['id'], $order);     $pos_b = array_search($b['id'], $order);     return $pos_a - $pos_b; });  var_dump($array); 

The key to this working is having the values that are being compared, be the positions of the ids within the $order array.

The comparison function works by finding the positions of the ids of two items to be compared within the $order array. If $a['id'] comes before $b['id'] in the $order array, then the return value of the function will be negative ($a is less so "floats" to the top). If $a['id'] comes after $b['id'] then the function returns a positive number ($a is greater so "sinks" down).

Finally, there is no special reason for using a closure; it's just my go-to way of writing these sorts of throwaway functions quickly. It could equally use a normal, named function.

like image 131
salathe Avatar answered Oct 19 '22 09:10

salathe


Extending salathe's answer for this additional requirement:

Now what happens when I add items to the array and not to the sort? I don't care what order they appear, as long as it comes after the ones that I did specify.

You need to add two additional conditions in the sorting function:

  1. A "dont care" item must be considered greater than whitelisted items
  2. Two "dont care" items must be considered equal

So the revised code would be:

$order = array(     3452342,     5867867,     7867867,     1231233 ); $array = array(     array("id" => 7867867, "title" => "Must Be #3"),     array("id" => 3452342, "title" => "Must Be #1"),     array("id" => 1231233, "title" => "Must Be #4"),     array("id" => 5867867, "title" => "Must Be #2"),     array("id" => 1111111, "title" => "Dont Care #1"),     array("id" => 2222222, "title" => "Dont Care #2"),     array("id" => 3333333, "title" => "Dont Care #3"),     array("id" => 4444444, "title" => "Dont Care #4") );  shuffle($array);  // for testing var_dump($array); // before  usort($array, function ($a, $b) use ($order) {     $a = array_search($a["id"], $order);     $b = array_search($b["id"], $order);     if ($a === false && $b === false) { // both items are dont cares         return 0;                       // a == b     } else if ($a === false) {          // $a is a dont care         return 1;                       // $a > $b     } else if ($b === false) {          // $b is a dont care         return -1;                      // $a < $b     } else {         return $a - $b;                 // sort $a and $b ascending     } }); var_dump($array); // after 

Output:

Before                         |  After -------------------------------+------------------------------- array(8) {                     |  array(8) {   [0]=>                        |    [0]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(4444444)               |      int(3452342)     ["title"]=>                |      ["title"]=>     string(12) "Dont Care #4"  |      string(10) "Must Be #1"   }                            |    }   [1]=>                        |    [1]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(3333333)               |      int(5867867)     ["title"]=>                |      ["title"]=>     string(12) "Dont Care #3"  |      string(10) "Must Be #2"   }                            |    }   [2]=>                        |    [2]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(1231233)               |      int(7867867)     ["title"]=>                |      ["title"]=>     string(10) "Must Be #4"    |      string(10) "Must Be #3"   }                            |    }   [3]=>                        |    [3]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(1111111)               |      int(1231233)     ["title"]=>                |      ["title"]=>     string(12) "Dont Care #1"  |      string(10) "Must Be #4"   }                            |    }   [4]=>                        |    [4]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(5867867)               |      int(2222222)     ["title"]=>                |      ["title"]=>     string(10) "Must Be #2"    |      string(12) "Dont Care #2"   }                            |    }   [5]=>                        |    [5]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(2222222)               |      int(1111111)     ["title"]=>                |      ["title"]=>     string(12) "Dont Care #2"  |      string(12) "Dont Care #1"   }                            |    }   [6]=>                        |    [6]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(3452342)               |      int(3333333)     ["title"]=>                |      ["title"]=>     string(10) "Must Be #1"    |      string(12) "Dont Care #3"   }                            |    }   [7]=>                        |    [7]=>   array(2) {                   |    array(2) {     ["id"]=>                   |      ["id"]=>     int(7867867)               |      int(4444444)     ["title"]=>                |      ["title"]=>     string(10) "Must Be #3"    |      string(12) "Dont Care #4"   }                            |    } }                              |  } 
like image 41
Salman A Avatar answered Oct 19 '22 07:10

Salman A