phparrayssortingmultidimensional-arrayarray-multisort

Custom sort multidimensional array using array_multisort()


I have the following array:

$array = [
    'note' => [],
    'year' => ['2011','2010', '2012'],
    'type' => ['conference', 'journal', 'conference'],
];

And I use the following function to sort the array using the field type and another array:

function array_multisort_by_order(array $array, $by, array $order)
{
    $order = array_flip($order);
    $params[] = $array[$by];
    foreach($params[0] as &$v) $v = $order[$v];
    foreach($array as &$v) $params[] = &$v; unset($v);
    call_user_func_array('array_multisort', $params);
    return $array;
}

When I call the following function I get the following error:

$array = array_multisort_by_order($array, 'type', array('conference', 'journal'));

print_r($array['type']);

Error:

Warning: array_multisort(): Array sizes are inconsistent.

I know that arrays are inconsistent. Is there a better function to use?

Please check: codepad

Desired Output:

Array
(
[note] => Array
    (
        [0] => 
        [1] => 
        [2] => 
    )

[year] => Array
    (
        [0] => 2011
        [1] => 2012
        [2] => 2010
    )

[type] => Array
    (
        [0] => conference
        [1] => conference
        [2] => journal
    )

)

Example 2:

Array

$array = [
    'note' => ['test1', 'test2'],
    'year' => ['2011', '2012'],
    'type' => ['conference', 'journal', 'conference'],
];

Desired Result 2

Array
(
[note] => Array
    (
        [0] => test1
        [1] => 
        [2] => tes2
    )

[year] => Array
    (
        [0] => 2011
        [1] => 2012
        [2] => 
    )

[type] => Array
    (
        [0] => conference
        [1] => conference
        [2] => journal
    )

)

Solution

  • OK, so, one of the first solutions that comes to mind is adding in the empty values to make them consistent:

    function array_multisort_by_order(array $array, $by, array $order)
    {
         $max = max(array_map('count',$array));
        //or, alternatively, depending on input (if there are no 'complete' subarrays):
        //$max = max(array_map(function($arr){return max(array_keys($arr));},$array))+1;
    
        //ADDITION: negative numeric keys:
        $min = min(array_map(function($arr){return min(array_keys($arr));},$array));
        $width = $max - min(0,$min);
    
        foreach($array as &$sub){
            // $addin = array_diff_key(array_fill(0,$max,null),$sub);
            // $addin changed for negative keys:
            $addin = array_diff_key(array_combine(range($min,$max),array_fill(0,$width,null)),$sub);
            $sub = $addin + $sub;
            ksort($sub);
        }
        $order = array_flip($order);
        $params[] = $array[$by];
        foreach($params[0] as &$v) $v = $order[$v];
        foreach($array as &$v) $params[] = &$v; unset($v);
        call_user_func_array('array_multisort', $params);
        //no closeures here:
        //foreach($array as &$sub) $sub = array_filter(function($a){return !is_null($a);},$sub);
        $filter = create_function('$a','return !is_null($a);');
        foreach($array as &$sub) $sub = array_filter($sub,$filter);
        return $array;
    }