简体   繁体   中英

Sort array rows by one column in tiers of 10, then by another column

How to do 2-tier sorting on an array using below criteria:

edd value groups:

  1. 1-10
  2. 11-20
  3. 21-30

The array is

$var_array = [
    ['name' => 'product1', 'edd'=>16, 'price' => 89],
    ['name' => 'product2', 'edd'=>21, 'price' => 99],
    ['name' => 'product3', 'edd'=>2, 'price' => 110],
    ['name' => 'product4', 'edd'=>14, 'price' => 102],
    ['name' => 'product5', 'edd'=>8, 'price' => 119],
    ['name' => 'product6', 'edd'=>6, 'price' => 123],
    ['name' => 'product7', 'edd'=>26, 'price' => 93],
    ['name' => 'product8', 'edd'=>27, 'price' => 105],
    ['name' => 'product9', 'edd'=>18, 'price' => 133],
];

First sort the edd , and then sort the price within each edd group level.

Expected result

$var_array = [
    ['name' => 'product3', 'edd' => 2, 'price' => 110],
    ['name' => 'product5', 'edd' => 8, 'price' => 119],
    ['name' => 'product6', 'edd' => 6, 'price' => 123],

    ['name' => 'product1', 'edd' => 16, 'price' => 89],
    ['name' => 'product4', 'edd' => 14, 'price' => 102],
    ['name' => 'product9', 'edd' => 18, 'price' => 133],

    ['name' => 'product7', 'edd' => 26, 'price' => 93],
    ['name' => 'product2', 'edd' => 21, 'price' => 99],
    ['name' => 'product8', 'edd' => 27, 'price' => 105],
];

You can use array_reduce and array_map

$var_array = array(
    array('name' => 'product1', 'edd'=>16, 'price' => 89),
    array('name' => 'product2', 'edd'=>21, 'price' => 99),
    array('name' => 'product3', 'edd'=>2, 'price' => 110),
    array('name' => 'product4', 'edd'=>14, 'price' => 102),
    array('name' => 'product5', 'edd'=>8, 'price' => 119),
    array('name' => 'product6', 'edd'=>6, 'price' => 123),
    array('name' => 'product7', 'edd'=>26, 'price' => 93),
    array('name' => 'product8', 'edd'=>27, 'price' => 105),
    array('name' => 'product9', 'edd'=>18, 'price' => 133),
);

//Group array and sort key
$temp = array_reduce($var_array, function($c, $v){
    $c[ ceil($v["edd"] / 10) * 10 ][] = $v;
    return $c;
}, array());

ksort($temp);

//Sort array
$temp = array_map(function ($n) {
    usort($n, function($a, $b){
            return $a["price"] - $b["price"];
        });
    return $n;
}, $temp );


//Make 2 dimentional array into 1
$result = array_reduce($temp, 'array_merge', array());

echo "<pre>";
print_r( $result );
echo "</pre>";

This will result to:

Array
(
    [0] => Array
        (
            [name] => product3
            [edd] => 2
            [price] => 110
        )

    [1] => Array
        (
            [name] => product5
            [edd] => 8
            [price] => 119
        )

    [2] => Array
        (
            [name] => product6
            [edd] => 6
            [price] => 123
        )

    [3] => Array
        (
            [name] => product1
            [edd] => 16
            [price] => 89
        )

    [4] => Array
        (
            [name] => product4
            [edd] => 14
            [price] => 102
        )

    [5] => Array
        (
            [name] => product9
            [edd] => 18
            [price] => 133
        )

    [6] => Array
        (
            [name] => product7
            [edd] => 26
            [price] => 93
        )

    [7] => Array
        (
            [name] => product2
            [edd] => 21
            [price] => 99
        )

    [8] => Array
        (
            [name] => product8
            [edd] => 27
            [price] => 105
        )

)

This 2-rule sort can be simply done with usort() . Use ceil($number / 10) to make groups of 1 - 10, 11 - 20, etc. I want 0 - 9, 10 - 19, 20 - 21, use intdiv($number, 10) .

  1. Sort by the floored tenth of the edd values ascending, then
  2. Sort by price value ascending.

Code: ( Demo )

usort(
    $var_array,
    fn($a, $b) => [ceil($a['edd'] / 10), $a['price']]
                  <=>
                  [ceil($b['edd'] / 10), $b['price']]
);

However, it will be more efficient to use array_multsort() because fewer function calls will be needed.

Code: ( Demo )

$groups = [];
$prices = [];
foreach ($var_array as $row) {
    $groups[] = ceil($row['edd'] / 10);
    $prices[] = $row['price'];
}
array_multisort($groups, $prices, $var_array);

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