Anuj Jain
Anuj Jain

Reputation: 87

Sort 3rd level data in descending order by column in 4th level of a multidimensional array

I have a complex multidimensional array; the structure is like this:

[
    [
        'countries' => [
            ['country_code' => 'US', 'growth' => 3.57],
            ['country_code' => 'CA', 'growth' => 4.77],
            ['country_code' => 'TT', 'growth' => 0],
        ],
        'group_name' => 'North America',
    ],
    [
        'countries' => [
            ['country_code' => 'BR', 'growth' => 2.19],
            ['country_code' => 'PE', 'growth' => 1.78],
            ['country_code' => 'UY', 'growth' => 8.83],
            ['country_code' => 'MX', 'growth' => 3.83],
        ],
        'group_name' => 'South America',
    ],
]

I want to sort the subarrays inside each countries entry (maybe by using array_multisort) so that they are sorted according to growth (highest first)

So that the sorted array will be:

[
    [
        'countries' => [
            ['country_code' => 'CA', 'growth' => 4.77],
            ['country_code' => 'US', 'growth' => 3.57],
            ['country_code' => 'TT', 'growth' => 0],
        ],
        'group_name' => 'North America',
    ],
    [
        'countries' => [
            ['country_code' => 'UY', 'growth' => 8.83],
            ['country_code' => 'MX', 'growth' => 3.83],
            ['country_code' => 'BR', 'growth' => 2.19],
            ['country_code' => 'PE', 'growth' => 1.78],
        ],
        'group_name' => 'South America',
    ],
]

Upvotes: 2

Views: 154

Answers (3)

mickmackusa
mickmackusa

Reputation: 47991

Via a foreach() loop, use array destructuring syntax to modify the countries data by reference. In the loop body, call usort() and order the subarray rows by growth in a descending direction.

Code: (Demo)

foreach ($array as ['countries' => &$countries]) {
    usort($countries, fn($a, $b) => $b['growth'] <=> $a['growth']);
}
var_export($array);

The same technique can be functionally styled with array_map() to teturn a new mutated copy of the data.

Code: (Demo)

var_export(
    array_map(
        function ($set) {
            usort($set['countries'], fn($a, $b) => $b['growth'] <=> $a['growth']);
            return $set;
        },
        $array
    )
);

Upvotes: 0

feeela
feeela

Reputation: 29932

I've used my following sorting function for years now:

/**
 * sorting array of associative arrays - multiple row sorting using a closure
 * see also: the-art-of-web.com/php/sortarray/
 * @param array $data input-array
 * @param string|array $fields array-keys
 * @license Public Domain
 * @return array
 */
function sortArray( $data, $field )
{
    $field = (array) $field;
    uasort( $data, function($a, $b) use($field) {
        $retval = 0;
        foreach( $field as $fieldname )
        {
            if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] );
        }
        return $retval;
    } );
    return $data;
}


// example call, sort by 'growth' first and by 'country_code' afterwards
// this would be equal to a MySQL 'ORDER BY `growth` ASC, `country_code` ASC'
foreach( $countryArray as &$item )
{
    $item['countries'] = sortArray( $item['countries'], array( 'growth', 'country_code' ) );
}

Upvotes: 0

Mr. Llama
Mr. Llama

Reputation: 20909

Worst case scenario, you make your own sort function and use usort.
It's actually designed for these sorts of things.

In your case, you'll pass $arr[$i]['countries'] and have the comparison function sort based on $arr['growth'].

Upvotes: 2

Related Questions