17

I already got this question in Stack Overflow, but sadly it's in javascript - Sort a JavaScript array based on another array

and I want it in PHP

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

to match the arrangement of this array:

sortingArr = array("5","4","3","2","1");

and the output I'm looking for:

$data = array(
    "item3"=>"5",
    "item5"=>"4",
    "item2"=>"3",
    "item4"=>"2",
    "item1"=>"1"
 );
2
  • You could asort() both of them. Commented Jun 27, 2013 at 8:20
  • Use usort(), with a comparison function that compares the positions of the values in $sortingArr. Commented Jun 27, 2013 at 8:23

9 Answers 9

13

For a detailed answer, why array_multisort does not match your needs, view this answer, please: PHP array_multisort not sorting my multidimensional array as expected

In short: You want to sort an array based on a predefined order. The Answer is also given over there, but i copied one solution to this answer, too:

Use usort and array_flip, so you be able to turn your indexing array (ValueByPosition) into a PositionByValue Array.

    $data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

usort($data, "sortByPredefinedOrder");

function sortByPredefinedOrder($leftItem, $rightItem){
  $order = array("5","4","3","2","1");

  $flipped = array_flip($order);

  $leftPos = $flipped[$leftItem];
  $rightPos = $flipped[$rightItem];
  return $leftPos >= $rightPos;   
}

print_r($data);
// usort: Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )
// uasort: Array ( [item3] => 5 [item5] => 4 [item2] => 3 [item4] => 2 [item1] => 1 )

However this would require you to predict all possible items inside the predefined order array, or thread other items in an appropriate way.

If you want to maintain the assoc keys, use uasort instead of usort.

10

Pretty simple ?

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

$sortingArr = array("5","4","3","2","1");

$result = array(); // result array
foreach($sortingArr as $val){ // loop
    $result[array_search($val, $data)] = $val; // adding values
}
print_r($result); // print results

Output:

Array
(
    [item3] => 5
    [item5] => 4
    [item2] => 3
    [item4] => 2
    [item1] => 1
)
2
  • 2
    I don't think that this is a good memory efficient solution. The usort function is much more easier and faster in that case. But still this is a working solution for small arrays. BR. Commented Jul 8, 2014 at 7:07
  • 1
    As long as this isn't done in a critical part of the application and the data is rather small it will do its work in an easy to understand way. Commented Aug 5, 2015 at 8:31
2

using usort() the right way i think

Sort an array by values using a user-defined comparison function

you can do as follow:

$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);

$sortingArr = array("5","4","3","2","1");

$keys = array_flip($sortingArr);

usort($data, function ($a, $b) use ($keys) {
    return $keys[$a] > $keys[$b] ? 1 : -1;
});

print_r($data);

// Output
// Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )

live example: https://3v4l.org/75cnu

2

I'm pretty proud of my solution:

uasort($data, function($a, $b) use ($sortingArr) {  
    return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});

Working example: https://3v4l.org/bbIk2

  1. It uses uasort to maintain the key-value associations as the OP requested. (unlike @hassan's otherwise elegant solution)
  2. It doesn't require that every element in the $data array be present in the sorting array. (like @HamZa's solution)
  3. It's brief.
  4. It uses the spaceship operator <=> for comparison instead of more verbose logic.

Code:

1

Look at my following snippet to sort your array based on another array:

$res_arr = array(); 
for ($i = 0; $i < count($sortingArr); $i++) {
     for ($j = 0; $j < count($data); $j++) {
          if($data[$j] == $sortingArr[$i]) {
             $res_arr[] = $data[$j];
             break;
          }
     }
}
// $res_array is your sorted array now
4
  • This is a little late, but why do you use a break at the end? Commented Mar 9, 2019 at 10:19
  • The break stops the further iteration of the inner loop when the corresponding entry is found. It works without but you save some extra iterations of the inner loop. Commented Mar 10, 2019 at 12:40
  • 1
    The break is only if you're sure you'll have 1 value of each type, correct? Commented Mar 10, 2019 at 14:17
  • Yes correct. Good point, so if you have multiple items of the same point, you have to remove the break Commented Mar 10, 2019 at 14:42
1

Look at code snippet to make a multidimensional array sort in order of input

$input_format_list = [4, 1];
$data = array(
    "0" => array(
        "School" => array(
            "id" => 1,
             "name" => "ST.ANN'S HIGH SCHOOL",
        )
    ),     
    "1" => array(
        "School" => array(
            "id" => 4,
            "name" => "JYOTI VIDHYA VIHAR",
        )
    )
);   

$result = array(); // result array
foreach($input_format_list as $key => $value){ // loop
    foreach ($data as $k => $val) {
        if ($data[$k]['School']['id'] === $value) {
           $result[$key] = $data[$k];
        }
    }            
}            
return $result;
0

Take a look at array_multisort. I'm not completely sure how to use it, as I have never found a practical use for it (I prefer to use usort to clearly define my terms), but it might work for you.

6
  • 1
    I don't think array_multisort() does what he needs. It will sort one array normally, and then reorder the other array correspondingly. Commented Jun 27, 2013 at 8:23
  • So if the first array is the one that contains the desired order, shouldn't that mean putting the $data array as the second one sort it accordingly...? I dunno, like I said, never used that function! Commented Jun 27, 2013 at 8:24
  • I haven't used it, either, but the examples on the documentation page don't seem to match what he wants. Look at Example #1. It doesn't keep either input in its original order. Commented Jun 27, 2013 at 8:27
  • I've used it for sorting tables based off a user input its certainly a wierd function but sometimes useful I can post up an example but its not directly related to your question i'm afraid Commented Jun 27, 2013 at 8:28
  • See my post for an example, how array multisort works. No it wont work. array_multisort will "sort" the array, definining the order and move the other array's entries relatively up or down. Not what needed here. Commented Jun 27, 2013 at 8:44
0
<?php 
$data = array(
   "item1"=>"1",
   "item2"=>"3",
   "item3"=>"5",
   "item4"=>"2",
   "item5"=>"4"
);
$result=array_flip($data);

krsort($result);

$result=array_flip($result);

print_r($result);

//use rsort for the index array

$sortingArr = array("5","4","3","2","1");

print_r($sortingArr);
2
  • 1
    It does really not make sense to sort the values of $data by values. Since $sortingArr may not be descending values. Also using array_flip and then krsort is just ugly, you could use rsort directly. Commented Jun 27, 2013 at 8:34
  • $sortingArr also sorted in descending order by using rsort. Both arrays are available in descending order now Commented Jun 27, 2013 at 8:35
0

Expanding on the Answer of Andrew, if you want the undefined entries in the sorting array to appear at the end of the output array:

uasort($currentTags, function ($a, $b) use ($sortingArr) {
    if (in_array($a, $sortingArr) && !in_array($b, $sortingArr)) return -1;
    if (!in_array($a, $sortingArr) && in_array($b, $sortingArr)) return 1;
    if (!in_array($b, $sortingArr)) return -1;
    return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.