PHP - Sort Multi-Dimensional Array by Another Array

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



Leave a reply



Submit