简体   繁体   中英

logic to sort the multidimensional product array

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:

  • It switches the sorting criteria and selects the proper sorting callback (from the functions that were defined separately) to use with usort . If an unsupported value has been supplied, it will return the original order.
  • The array is always sorted ascending (even if some bogus value is supplied as the order). If descending order is defined, we return the sorted array in reverse order by using array_reverse .
  • Since you've specified that only width should be used for sorting size, it is sorted by casting size values to integer (since the integer value only considers the numbers up to the first non-numeric character).
  • Sorting by price requires extraction of the amount, which is done through 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.
  • Both sorting functions utilize the spaceship operator .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM