简体   繁体   中英

How to sort 3rd level subarrays using 4th level values in a multi-dimensional array?

I am trying to sort each Rates array by Price from low to high (ascending). I cannot figure it out looking at other solutions.

*Note that there are multiple subarrays like 13188 within the main array.

$array = array(
    13188 => array(
        'Rates' => array(
            0 => array(
                       'RateName' => 'Standard Rate',
                       'Price' => 499.56
                 ),
            18739 => array(
                       'RateName' => 'Second Rate',
                       'Price' => 449.6
                 )
        )
    )
)

I want to have this result:

$array = array(
    13188 => array(
        'Rates' => array(
            18739 => array(
                       'RateName' => 'Second Rate',
                       'Price' => 449.6
                 ),
            0 => array(
                       'RateName' => 'Standard Rate',
                       'Price' => 499.56
                 )
        )
    )
)

As you can see, the Rates subarray is sorted by Price . This means that the Price of 18739 is lower than the Price of 0 within the Rates subarray.

You can use http://php.net/manual/en/function.uasort.php for each elemnts on your arr. That function takes "Callback" ( http://php.net/manual/en/language.types.callable.php ) in which you can describe your rules of conduct.

<?php

$arr = [
    13188 => [
        'Rates' => [
            0 => [
                'RatteName' => 'Second Rate',
                'Price' => 499.6
            ],
            18739 => [
                'RatteName' => 'Second Rate',
                'Price' => 499.56
            ],
            1 => [
                'RatteName' => 'Second Rate',
                'Price' => 15.5
            ],
            2 => [
                'RatteName' => 'Second Rate',
                'Price' => 14
            ],
            3 => [
                'RatteName' => 'Second Rate',
                'Price' => 100
            ]

        ]
    ],
    13189 => [
        'Rates' => [
            0 => [
                'RatteName' => 'Second Rate',
                'Price' => 5
            ],
            18739 => [
                'RatteName' => 'Second Rate',
                'Price' => 7
            ],
            1 => [
                'RatteName' => 'Second Rate',
                'Price' => 18.3
            ],
            2 => [
                'RatteName' => 'Second Rate',
                'Price' => 2
            ],
            3 => [
                'RatteName' => 'Second Rate',
                'Price' => 22
            ]

        ]
    ],
    13140 => [
        'Rates' => [
            0 => [
                'RatteName' => 'Second Rate',
                'Price' => 1
            ],
            18739 => [
                'RatteName' => 'Second Rate',
                'Price' => 13
            ],
            1 => [
                'RatteName' => 'Second Rate',
                'Price' => 866.17
            ],
            2 => [
                'RatteName' => 'Second Rate',
                'Price' => 19
            ],
            3 => [
                'RatteName' => 'Second Rate',
                'Price' => 25
            ]

        ]
    ],
];

foreach($arr as $key => &$arrRates){
    $sortArr = $arrRates['Rates'];
    uasort($sortArr, function($firstArr, $secondArr){
        if ($firstArr['Price'] == $secondArr['Price']) {
            return 0;
        }
        return ($firstArr['Price'] < $secondArr['Price']) ? -1 : 1;
    });
    $arrRates['Rates'] = $sortArr;
}

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

Array
(
    [13188] => Array
        (
            [Rates] => Array
                (
                    [2] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 14
                        )

                    [1] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 15.5
                        )

                    [3] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 100
                        )

                    [18739] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 499.56
                        )

                    [0] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 499.6
                        )

                )

        )

    [13189] => Array
        (
            [Rates] => Array
                (
                    [2] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 2
                        )

                    [0] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 5
                        )

                    [18739] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 7
                        )

                    [1] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 18.3
                        )

                    [3] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 22
                        )

                )

        )

    [13140] => Array
        (
            [Rates] => Array
                (
                    [0] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 1
                        )

                    [18739] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 13
                        )

                    [2] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 19
                        )

                    [3] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 25
                        )

                    [1] => Array
                        (
                            [RatteName] => Second Rate
                            [Price] => 866.17
                        )

                )

        )

)

There are two "styles" for ordering your Rates subarrays in ascending order while preserving keys. The best tool for this job is uasort() because it allows you to perform a customized sort on the array that it is fed. The a in uasort() means "preserve the original keys".

The "magic" of the "user-defined sort" is in the second parameter -- a function call. No matter what function you decide to call, uasort() will be delivering values in sets of two to the function for comparison (I am naming these values $a and $b ). How you compare these two variables (and in what order you compare them) will determine the outcome of the sort.

I will be using the modern php "spaceship operator" for comparisons, but you may elect to use an older / more verbose set of "greater than, less than, equal to" conditions.

The first method "modifies by reference" with the & symbol (instead of processing a copy of the array in the foreach loop, and the second method simply overwrites the original array on each iteration by referencing the necessary keys.

Method #1 : "modify by reference"

foreach($array as &$subarray){  // modify $subarray by reference using &
    uasort($subarray['Rates'],function($a,$b){
        return $a['Price']<=>$b['Price']; // $b<=>$a would mean DESC order
    });
}

Method #2 : "iterative overwrite"

foreach($array as $key=>$subarray){  // iterate
    $rates=$subarray['Rates'];  // isolate the Rates subarray
    uasort($rates,function($a,$b){  // sort the Rates subarray
        return $a['Price']<=>$b['Price'];  // ascending order
    });
    $array[$key]['Rates']=$rates;  // overwrite the original array
}

To clarify a point that is specific to this case, you should NOT use array_multisort() because it will re-index your Rates subarray (overwrite the original numeric keys starting from zero). For cases when you have associative keys -- go for it... just not this time.

DON'T USE THIS METHOD FOR YOUR CASE:

foreach($array as &$subarray){  // modify $subarray by reference using &
    array_multisort(array_column($subarray['Rates'],'Price'),$subarray['Rates']);
}

NOR THIS ONE:

foreach($array as $key=>$subarray){  // iterate and overwrite
    $rates=$subarray['Rates'];
    array_multisort(array_column($rates,'Price'),$rates);
    $array[$key]['Rates']=$rates;
}

Here is a demo page that has all four methods set up so that you can run them and see the output for yourself: Demo Link

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