Sort a multidimensional array descending by subarray count and preserve first level keys
Asked Answered
F

4

29

I have an array such as:

$array = [
    'DEF' => [
        ['type' => 1, 'id' => 1212, 'name' => 'Jane Doe', 'current' => 1],
        ['type' => 1, 'id' => 3123121, 'name' => 'Door', 'current' => null],
    ],
    'ABC' => [
        ['type' => 1, 'id' => 1234, 'name' => 'John Doe', 'current' => null],
    ],
    'WW' => [
        ['type' => 1, 'id' => 1212, 'name' => 'Jane Doe', 'current' => 1],
        ['type' => 1, 'id' => 3123121, 'name' => 'Door', 'current' => null],
        ['type' => 1, 'id' => 64646, 'name' => 'Floor', 'current' => null],
    ]
];

And I want to sort this array by number ( count() ) of inner-array items descending (i.e. most items first), so I will have this array:

[
    'WW' => [
        ['type' => 1, 'id' => 1212, 'name' => 'Jane Doe', 'current' => 1],
        ['type' => 1, 'id' => 3123121, 'name' => 'Door', 'current' => null],
        ['type' => 1, 'id' => 64646, 'name' => 'Floor', 'current' => null],
    ],
    'DEF' => [
        ['type' => 1, 'id' => 1212, 'name' => 'Jane Doe', 'current' => 1],
        ['type' => 1, 'id' => 3123121, 'name' => 'Door', 'current' => null],
    ],
    'ABC' => [
        ['type' => 1, 'id' => 1234, 'name' => 'John Doe', 'current' => null],
    ]
];

Can anyone suggest an efficient way to do so? Thanks.

Foremost answered 15/9, 2011 at 15:39 Comment(2)
Why not usort php.net/manual/en/function.usort.php ?Stannite
please use var_export for dumping arraysRedbug
R
40

Using uksort:

uksort($array, function($a, $b) { return count($b) - count($a); });

Using array_multisort:

array_multisort(array_map('count', $array), SORT_DESC, $array);

With PHP < 5.3:

function sort_cb($a, $b) {
    return count($b) - count($a);
}
uksort($array, 'sort_cb');
Redbug answered 15/9, 2011 at 15:42 Comment(5)
If you are using PHP < 5.3.0, you'll need to move that anonymous function out of there.Mixie
you should not use PHP < 5.3.0 ;)Redbug
The uksort() example didn't work as I lost my array keys ('ABC','DEF','WW') but the array_multisort() did work -- thanks!Foremost
Shouldn't that be usort instead of uksort?Pothead
uksort sorts by Keys. Keys cannot be arrays and count does not count anything. usort compares values, which can be arrays.Morello
A
4
<?php
function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return (count($a) > count($b)) ? -1 : 1;
}

$a = array(
"AA" => array(
        array('type'=>'1', 'id'=>'2'),
        array('type'=>'2', 'id'=>'2')),
'BB' => array(
        array('type'=>'1', 'id'=>'2'),
        array('type'=>'2', 'id'=>'2'),
        array('type'=>'5', 'id'=>'2')),
'CC' => array(
        array('type'=>'1', 'id'=>'2'))
);  

usort($a, "cmp");

print_r($a);
?>
Anaplastic answered 15/9, 2011 at 15:51 Comment(2)
If you use PHP 7, you can now just do count($a) <=> count($b); :)Torr
This was exactly what I needed, thank you.Weepy
M
1
$tempArr = $sortedArr = array();
foreach ($myArr as $k => $v) $tempArr[$k] = count($v);
asort($tempArr);
foreach ($tempArr as $k => $v) $sortedArr = $myArr[$k];

Note that this will break if any of the array values are not themselves arrays, you may want to add an is_array() check somewhere...

Meliorism answered 15/9, 2011 at 15:44 Comment(0)
C
0

If you are only worried about sorting on size and not the actual quality, you can use the simplest approach to sort descending and preserve keys with arsort().

Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are incomparable, otherwise - compare value by value (see following example)

In the event that you have multiple rows with the same size, then they will be further sorted descending based on their actual data.

Code: (Demo)

arsort($array);
var_export($array);
Cumulous answered 21/10, 2022 at 2:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.