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"
);
9 Answers 9
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
.
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
)
-
2I 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– Jacek Kowalewski2014年07月08日 07:07:15 +00:00Commented Jul 8, 2014 at 7:07
-
1As 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– flu2015年08月05日 08:31:06 +00:00Commented Aug 5, 2015 at 8:31
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
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
- It uses
uasort
to maintain the key-value associations as the OP requested. (unlike @hassan's otherwise elegant solution) - It doesn't require that every element in the $data array be present in the sorting array. (like @HamZa's solution)
- It's brief.
- It uses the spaceship operator
<=>
for comparison instead of more verbose logic.
Code:
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
-
This is a little late, but why do you use a break at the end?Wanjia– Wanjia2019年03月09日 10:19:15 +00:00Commented 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.alex– alex2019年03月10日 12:40:06 +00:00Commented Mar 10, 2019 at 12:40
-
1The break is only if you're sure you'll have 1 value of each type, correct?Wanjia– Wanjia2019年03月10日 14:17:15 +00:00Commented 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 breakalex– alex2019年03月10日 14:42:45 +00:00Commented Mar 10, 2019 at 14:42
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;
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.
-
1I don't think
array_multisort()
does what he needs. It will sort one array normally, and then reorder the other array correspondingly.Barmar– Barmar2013年06月27日 08:23:01 +00:00Commented 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!Niet the Dark Absol– Niet the Dark Absol2013年06月27日 08:24:22 +00:00Commented 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.Barmar– Barmar2013年06月27日 08:27:05 +00:00Commented 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 afraidDave– Dave2013年06月27日 08:28:59 +00:00Commented 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.dognose– dognose2013年06月27日 08:44:49 +00:00Commented Jun 27, 2013 at 8:44
<?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);
-
1It does really not make sense to sort the values of
$data
by values. Since$sortingArr
may not be descending values. Also usingarray_flip
and thenkrsort
is just ugly, you could usersort
directly.HamZa– HamZa2013年06月27日 08:34:03 +00:00Commented Jun 27, 2013 at 8:34 -
$sortingArr also sorted in descending order by using rsort. Both arrays are available in descending order nowSundar– Sundar2013年06月27日 08:35:40 +00:00Commented Jun 27, 2013 at 8:35
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);
});
asort()
both of them.usort()
, with a comparison function that compares the positions of the values in$sortingArr
.