I have to sort a multidimensional-array based on price or size but the problem is, it works with an issue, always the first array it sort is wrong, I tried using usort, etc but all of them giving the same result, we have a list of products that need to be sorted based on price or size. I find lots of answers and the problem remains the same. Product should be sort by based on price ie Low to high or Size will sort with width for example product dimension 120 x 60 so 120 is the width and it should be the last product
Function to Sort the multiDimensional array
function array_sort($array, $on, $order=SORT_ASC){
$new_array = array();
$sortable_array = array();
if (count($array) > 0) {
foreach ($array as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
if ($k2 == $on) {
$sortable_array[$k] = $v2;
}
}
} else {
$sortable_array[$k] = $v;
}
}
switch ($order) {
case SORT_ASC:
asort($sortable_array);
break;
case SORT_DESC:
arsort($sortable_array);
break;
}
foreach ($sortable_array as $k => $v) {
$new_array[$k] = $array[$k];
}
}
return $new_array; }
Here is the array I want to sort
$sortingArray = Array(
'0' => Array(
'id' => 1287,
'data-price' => '£209.95',
'size' => '120 x 60'
),
'1' => Array(
'id' => 1263,
'data-price'=> '£14.95',
'size' => '18 x 13'
),
'2' => Array(
'id' => 1264,
'data-price' => '£15.95',
'size' => '20 x 15'
),
'3' => Array(
'id' => 1245,
'data-price' => '£29.95',
'size' => '30 x 20'
),
'4' => Array
(
'id' => 1315,
'data-price' => '£39.95',
'size' => '50 x 13'
),
'5' => Array(
'id' => 1275,
'data-price' => '£94.95',
'size' => '60 x 40'
),
'6' => Array
(
'id' => 1281,
'data-price' => '£119.95',
'size' => '75 x 50'
),
);
To Output result
$rectangleProductDetails = array_sort($sortingArray, 'size', SORT_ASC);
print_r($rectangleProductDetails);
Proposed solution:
function array_sort(array $array, string $on, string $order = 'ASC') {
$sortableArray = $array;
switch ($on) {
case 'size':
usort($sortableArray, 'sortBySize');
break;
case 'price':
usort($sortableArray, 'sortByPrice');
break;
default:
return $array;
break;
}
if (strtoupper($order) === 'DESC') {
return array_reverse($sortableArray);
}
return $sortableArray;
}
function sortByPrice(array $a, array $b) {
return (float) mb_substr($a['data-price'], 1) <=> (float) mb_substr($b['data-price'], 1);
}
function sortBySize(array $a, array $b) {
return (int) $a['size'] <=> (int) $b['size'];
}
How it works:
usort
. If an unsupported value has been supplied, it will return the original order.array_reverse
.mb_substr($priceVariable, 1)
(it eliminates the first character). Note that substr
wouldn't work here, as the pound sign is a multibyte character so the multibyte version of the substring function has to be used. Lastly, note that the $on
sorting criteria doesn't match the array keys exactly (I use 'price'
instead of 'data-price'
; they can match - like 'size'
does - but don't have to). The benefit of this is that if an index in the array changes, you only need to modify the sorting callbacks, instead of having to do the modification in every single place where you call your custom array_sort
function.
you need to cast size as int
maybe something like
usort($sortingArray, function($a, $b) {
//you can calculate your size and sort the result
//or split it into 2 number and then sort it
return intval($a["size"]) < intval($b["size"]) ? -1 : 1;
});
Reading what you are trying to achieve I think the following would be a proper approach on achieving a solution.
Since you require several different ways of sorting the array on the values of its fields, with their own needs, I think a strategy kind of pattern will fit this scenario.
For this I defined several functions, one to sanitize the string containing the price and then compare them using the space ship operator.
For the size, we simply obtain the width and compare the intvals.
And finally the default will just apply regular comparison.
function priceSort($on)
{
return function ($item, $other) use ($on) {
$itemPrice = filter_var($item[$on], FILTER_SANITIZE_NUMBER_FLOAT);
$otherPrice = filter_var($other[$on], FILTER_SANITIZE_NUMBER_FLOAT);
return floatval($itemPrice) <=> floatval($otherPrice);
};
}
function widthSort($on)
{
return function ($item, $other) use ($on) {
$itemWidth = explode('x', str_replace(' ', '', $item[$on]))[0];
$otherWidth = explode('x', str_replace(' ', '', $other[$on]))[0];
return intval($itemWidth) <=> intval($otherWidth);
};
}
function defaultSort($on)
{
return function ($item, $other) use ($on) {
return $item[$on] <=> $other[$on];
};
}
function determineSortStrategy($on)
{
switch ($on) {
case 'size':
$strategy = widthSort($on);
break;
case 'data-price':
$strategy = priceSort($on);
break;
default:
$strategy = defaultSort($on);
break;
}
return $strategy;
}
function orderBased($strategy, $order)
{
if ($order === SORT_DESC) {
$strategy = function ($item, $other) use ($strategy) {
return -1 * $strategy($item, $other);
};
}
return $strategy;
}
function array_sort($array, $on = 'id', $order = SORT_ASC)
{
$strategy = determineSortStrategy($on);
$strategy = orderBased($strategy, $order);
usort($array, $strategy);
return $array;
}
$result = array_sort($sortingArray, 'data-price', SORT_DESC);
echo '<pre>';
print_r($result);
echo '</pre>';
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.