Skip to content
Advertisement

Multi-dimensional sorting with variable amount of sorting criteria

I’m looking for a way to sort a multi-dimensional array, based on a variable amount of sorting keys.

Take the following example:

        Array
(
    [0] => Array
        (
            [userId] => 2
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 2
                    [watches] => 3
                    [balls] => 2
                )

        )

    [1] => Array
        (
            [userId] => 1
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 3
                    [watches] => 4
                    [balls] => 1
                )

        )

    [2] => Array
        (
            [userId] => 3
            [amounts] => Array
                (
                    [pencils] => 3
                    [phones] => 3
                    [watches] => 4
                    [balls] => 2
                )

        )

)

I want, for example, to sort this array by phones first, if that value is the same, by watch, then by balls and then by pencils.

So basically, the result should be:

        Array
(
    [0] => Array
        (
            [userId] => 3
            [amounts] => Array
                (
                    [pencils] => 3
                    [phones] => 3
                    [watches] => 4
                    [balls] => 2
                )

        )

    [1] => Array
        (
            [userId] => 1
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 3
                    [watches] => 4
                    [balls] => 1
                )

        )

    [2] => Array
        (
            [userId] => 2
            [amounts] => Array
                (
                    [pencils] => 6
                    [phones] => 2
                    [watches] => 3
                    [balls] => 2
                )

        )

)

Now, the tricky part is that in the original array, the stuff in the amounts array (e.g. pencils, phones, watches, balls) can be variable. So it might be that there are 4 like in the example, but it could also be that there’s just one item, or 5 or…

I was getting my toes wet with sorting, trying out stuff like

usort($array, function($a, $b) {
    return $a['amounts']['phones'] <=> $b['amounts']['watch'];
});

but I’m stuck now and unsure how to unblock myself.

Any help is much appreciated! I’m using PHP 7.

Update:

As requested in the comments, here’s a var_export from the first array:

array (
  0 => 
  array (
    'userId' => '2',
    'amounts' => 
    array (
      'pencils' => '6',
      'phones' => '2',
      'watches' => '3',
      'balls' => '2',
    ),
  ),
  1 => 
  array (
    'userId' => '1',
    'amounts' => 
    array (
      'pencils' => '6',
      'phones' => '3',
      'watches' => '4',
      'balls' => '1',
    ),
  ),
  2 => 
  array (
    'userId' => '3',
    'amounts' => 
    array (
      'pencils' => '3',
      'phones' => '3',
      'watches' => '4',
      'balls' => '2',
    ),
  ),
)

Advertisement

Answer

Ok, so usort() is a correct path to be on. To solve this, you can pass in the priority array to the callback, loop over the priority array and check each parameter one by one. If any of them in the process from start to end happens to be unequal, return their comparison difference. You can return 0 in the end, meaning keep elements as is in the sort order since they are equal.

$priority = array('phones','watches','balls','pencils');

usort($array,function($a,$b) use ($priority){
    foreach($priority as $p){
        if($a['amounts'][$p] != $b['amounts'][$p]) return $b['amounts'][$p] <=> $a['amounts'][$p];
    }
        
    return 0;
});


print_r($array);
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement