17

OK, I already got this question in stackoverflow but sadly it's in javascript - Javascript - sort 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"
 );

Any idea how this can be done? Thanks.

Community
  • 1
  • 1
Rio Eduardo
  • 233
  • 2
  • 4
  • 8

9 Answers9

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.

Community
  • 1
  • 1
dognose
  • 20,360
  • 9
  • 61
  • 107
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
)
HamZa
  • 14,671
  • 11
  • 54
  • 75
  • 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. – Jacek Kowalewski Jul 08 '14 at 07: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. – flu Aug 05 '15 at 08: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

hassan
  • 7,812
  • 2
  • 25
  • 36
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
alex
  • 5,516
  • 2
  • 36
  • 60
  • This is a little late, but why do you use a break at the end? – Wanjia Mar 09 '19 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. – alex Mar 10 '19 at 12:40
  • 1
    The break is only if you're sure you'll have 1 value of each type, correct? – Wanjia Mar 10 '19 at 14:17
  • Yes correct. Good point, so if you have multiple items of the same point, you have to remove the break – alex Mar 10 '19 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;
Striped
  • 2,544
  • 3
  • 25
  • 31
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.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 1
    I don't think `array_multisort()` does what he needs. It will sort one array normally, and then reorder the other array correspondingly. – Barmar Jun 27 '13 at 08: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! – Niet the Dark Absol Jun 27 '13 at 08: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. – Barmar Jun 27 '13 at 08: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 – Dave Jun 27 '13 at 08: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. – dognose Jun 27 '13 at 08:44
  • i think this worked for me: array_multisort($sortingArr , SORT_ASC, $data, SORT_ASC); – Hayden Thring Mar 25 '16 at 00:47
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);
Sundar
  • 4,580
  • 6
  • 35
  • 61
  • 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. – HamZa Jun 27 '13 at 08:34
  • $sortingArr also sorted in descending order by using rsort. Both arrays are available in descending order now – Sundar Jun 27 '13 at 08:35
0

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:

Andrew
  • 8,363
  • 8
  • 43
  • 71
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);
});
Marcus Haase
  • 35
  • 1
  • 6