PHP - Sort multi-dimensional array by another array
There is no built-in function for this in PHP and i am unable to think of any custom function, which would do this using usort. But array_map is simple enough, imo, so why not use it instead?
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
Sort multidimensional array based on another array
Since you already have the ids in the desired sort order, the only barrier to sorting $images
efficiently is the inability to immediately fetch an image given its id. So let's fix that by reindexing $images
to use the id as the array key using array_column
(don't get thrown by the name, it can also be used for reindexing):
// array_column is only available in PHP 5.5+
$images = array_column($images, null, 'id');
After this it's trivial to get a sorted array:
$sortedImages = [];
foreach ($sort as $id) {
$sortedImages[] = $images[$id];
}
For PHP < 5.5 you can substitute the array_column
reindexing with this:
$imageIds = array_map(function($i) { return $i['id']; }, $images);
$images = array_combine($imageIds, $images);
Alternatively you can get an implementation written in PHP by the author of array_column
himself.
How to Sort a Multi-dimensional Array by Value
Try a usort. If you are still on PHP 5.2 or earlier, you'll have to define a sorting function first:
function sortByOrder($a, $b) {
return $a['order'] - $b['order'];
}
usort($myArray, 'sortByOrder');
Starting in PHP 5.3, you can use an anonymous function:
usort($myArray, function($a, $b) {
return $a['order'] - $b['order'];
});
With PHP 7 you can use the spaceship operator:
usort($myArray, function($a, $b) {
return $a['order'] <=> $b['order'];
});
Finally, in PHP 7.4 you can clean up a bit with an arrow function:
usort($myArray, fn($a, $b) => $a['order'] <=> $b['order']);
To extend this to multi-dimensional sorting, reference the second/third sorting elements if the first is zero - best explained below. You can also use this for sorting on sub-elements.
usort($myArray, function($a, $b) {
$retval = $a['order'] <=> $b['order'];
if ($retval == 0) {
$retval = $a['suborder'] <=> $b['suborder'];
if ($retval == 0) {
$retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
}
}
return $retval;
});
If you need to retain key associations, use uasort()
- see comparison of array sorting functions in the manual.
Custom sort a multidimensional array by subarray keys using another array
You can use usort()
on $array1
and pass the $array2
in as the sort order lookup array.
Code: (Demo)
$array1 = [
[536870914 => 34213897],
[536870914 => 34213905],
[536870915 => 34213921],
[536870914 => 34213913],
[536870915 => 34213929],
[536870917 => 34213937],
[536870925 => 34218049],
];
$array2 = [
536870925,
536870914,
536870915,
536870917,
];
usort($array1, function($a, $b) use ($array2) {
return array_search(key($a), $array2) <=> array_search(key($b), $array2);
});
var_export($array1);
To make this process more efficient, flip the lookup array in advance.
Code: (Demo)
$array2 = array_flip($array2);
usort($array1, function($a, $b) use ($array2) {
return $array2[key($a)] <=> $array2[key($b)];
});
var_export($array1);
If some ids from array1 are not represented in array2, you will need to determine how these outliers should be sorted. If you do not adjust for missing values in the lookup array, you will generate Notices and have an unexpected sorting outcome.
Here is a similar post that offers some guidance on that subject:
https://stackoverflow.com/a/52754080/2943403
PHP sort a multidimensional array by another array
The below comment in the usort documentation sounds like it might help you out. I'll try to update the code soon specific to your problem but it might push you in the right direction.
If you want to sort an array according to another array acting as a
priority list, you can use this function.<?php
function listcmp($a, $b)
{
global $order;
foreach($order as $key => $value)
{
if($a==$value)
{
return 0;
break;
}
if($b==$value)
{
return 1;
break;
}
}
}
$order[0] = "first";
$order[1] = "second";
$order[2] = "third";
$array[0] = "second";
$array[1] = "first";
$array[2] = "third";
$array[3] = "fourth";
$array[4] = "second";
$array[5] = "first";
$array[6] = "second";
usort($array, "listcmp");
print_r($array);
?>
Sort multidimensional array in PHP using foreach
array_multisort
sorts the array in place, it does not return the sorted array. You need to use it like this:
foreach ($slice1 as $col) {
array_multisort($col);
$slicesort[] = $col;
}
Having said this, array_multisort
is somewhat overkill here, and I'm not sure that you really need to create a copy of the array. This will do just fine:
foreach ($slice1 as &$col) {
sort($col);
}
This applies sort
to each array within $slice1
by reference, and thereby orders $slice1
in place.
PHP Sort associative multidimensional array by another array
This is a solution, but it is as ugly as the quality of the initial data you have:
<?php
$input = [
"title" => ["title 1", "title 2", "title 3", "title 4", "title 5", "title 6"],
"article" => ["01", "02", "03", "04", "05", "06"]
];
$order = ["03", "01", "04", "02"];
$output = [];
// pick ordered items
foreach($order as $article) {
$position = array_search($article, $input['article']);
foreach (array_keys($input) as $key) {
$output[$key][] = $input[$key][$position];
}
}
// fill in the rest
foreach ($input['article'] as $position => $article) {
foreach (array_keys($input) as $key) {
if (!in_array($article, $order)) {
$output[$key][] = $input[$key][$position];
}
}
}
var_dump($output);
The output obviously is:
array(2) {
["title"]=>
array(6) {
[0]=>
string(7) "title 3"
[1]=>
string(7) "title 1"
[2]=>
string(7) "title 4"
[3]=>
string(7) "title 2"
[4]=>
string(7) "title 5"
[5]=>
string(7) "title 6"
}
["article"]=>
array(6) {
[0]=>
string(2) "03"
[1]=>
string(2) "01"
[2]=>
string(2) "04"
[3]=>
string(2) "02"
[4]=>
string(2) "05"
[5]=>
string(2) "06"
}
}
How to filter multidimensional array based on another multidimensional array of exclusions?
Breaking your exclusion array into separate variables is not advisable because this will make your code harder / more tedious to maintain when you want to modify the exclusion list.
Iterate your products array just one time. Inside that loop, loop the attributes in each product having keys which match the first level keys in the exclusion array. This is what array_intersect_key()
does best and this prevents performing an unnecessary comparison on the Product ID
elements. As soon as you find a disqualifying condition to be satisfied, stop the inner loop for best efficiency.
Code #1 (Demo) *my recommendation
$result = [];
foreach ($products as $product) {
foreach (array_intersect_key($product, $exclusions) as $key => $value) {
if (in_array($value, $exclusions[$key])) {
continue 2;
}
}
$result[] = $product;
}
var_export($result);
Code #2: (Demo)
foreach ($products as $index => $product) {
foreach (array_intersect_key($product, $exclusions) as $key => $value) {
if (in_array($value, $exclusions[$key])) {
unset($products[$index]);
break;
}
}
}
var_export(array_values($products));
Code #3: (Demo)
var_export(
array_values(
array_filter(
$products,
function($product) use ($exclusions) {
return !array_filter(
array_intersect_key($product, $exclusions),
function($value, $key) use ($exclusions) {
return in_array($value, $exclusions[$key]);
},
ARRAY_FILTER_USE_BOTH
);
}
)
)
);
Code #4: (Demo)
var_export(
array_values(
array_filter(
$products,
fn($product) => !array_filter(
array_intersect_key($product, $exclusions),
fn($value, $key) => in_array($value, $exclusions[$key]),
ARRAY_FILTER_USE_BOTH
)
)
)
);
Code #1 uses continue 2;
to stop the halt the inner loop, avoid storing the current product in the output array, then return to the outer loop to carry on processing the next product.
Code #2 is directly modifying the $products
array. By unsetting products, the array may cease to be an indexed array (the keys may have gaps between integers). If desirable, call array_values()
after the loop to re-index the output.
Code #3 is using a functional style. It is common for language constructs (e.g. foreach()
) to outperform functional iterators, so I will assume this snippet (and Code #4) will be slightly slower than the first two. Furthermore, array_filter()
doesn't enjoy the early return that the foreach loops have with break
and continue
. In other words, Code #3 & #4 will continue checking against the exclusion array even if a disqualifying condition has already been satisfied for a given product. And if that wasn't enough, I simply find the syntax too convoluted.
Code #4 is the same as Code #3, but is using the slightly shorter "arrow function" syntax which is available from PHP7.4 and up. This affords the omission of use()
and some other characters, but I still find the snippet less intuitive/readable compared to Code #1 & #2.
PHP Sort Multidimensional Array Based on Multiple Criteria
I found a solution that uses array_multisort()
foreach ($arr as $key => $row) {
$wins[$key] = $row[1];
$losses[$key] = $row[2];
$ptsfor[$key] = $row[3];
}
array_multisort($wins, SORT_DESC, $losses, SORT_ASC, $ptsfor, SORT_DESC, $arr);
Related Topics
Convert PHP Array String into an Array
Supplied Key Param Cannot Be Coerced into a Private Key with Google APIs
Simple Xml Add Namespaced Child
Mail(): Smtp Server Response: 550 the Address Is Not Valid Error on Hmailserver
Display an Array in a Readable/Hierarchical Format
Nginx Issues Http 499 Error After 60 Seconds Despite Config. (PHP and Aws)
Create Programmatically a Product Using Crud Methods in Woocommerce 3
How to Use PHP to Connect to SQL Server
Group Duplicate Array Keys in a Multidimensional Array into Subarray
Pdo and MySQL Fulltext Searches
Default as First Option in Switch Statement
PHP Session-Based Flash Message
How Safe Is PHP Pdo Function: Lastinsertid
Mysqli Prepared Statement Num_Rows Returns 0 While Query Returns Greater Than 0