PHP array_multisort not sorting my multidimensional array as expected

10,675

With array Multisort, you can Sort depending on a column. This is a example, where you can easily sort by "all" available columns:

<?
$data['test1'] = array('volume' => 67, 'edition' => 2, 'name' => 6, 'type' => 2);
$data['test2'] = array('volume' => 86, 'edition' => 1, 'name' => 7, 'type' => 2);
$data['test3'] = array('volume' => 85, 'edition' => 6, 'name' => 8, 'type' => 2);
$data['test4'] = array('volume' => 98, 'edition' => 2, 'name' => 9, 'type' => 2);
$data['test5'] = array('volume' => 86, 'edition' => 6, 'name' => 10, 'type' => 2);
$data['test6'] = array('volume' => 67, 'edition' => 7, 'name' => 11, 'type' => 2);

//Create index rows
foreach ($data as $row) {
  foreach ($row as $key => $value){
    ${$key}[]  = $value; //Creates $volume, $edition, $name and $type arrays.
  }  
}

//ex: sort by edition asc, then by name DESC:

array_multisort($edition, SORT_ASC, $name, SORT_DESC, $data);

echo "<pre>";
print_r($data);
echo "</pre>";
?>

will result in (first by edition ASC, then by name DESC): (sorting by name ASC, will swap test4 and test1 ofc.)

Array
(
    [test2] => Array
        (
            [volume] => 86
            [edition] => 1
            [name] => 7
            [type] => 2
        )

    [test4] => Array
        (
            [volume] => 98
            [edition] => 2
            [name] => 9
            [type] => 2
        )

    [test1] => Array
        (
            [volume] => 67
            [edition] => 2
            [name] => 6
            [type] => 2
        )

    [test5] => Array
        (
            [volume] => 86
            [edition] => 6
            [name] => 10
            [type] => 2
        )

    [test3] => Array
        (
            [volume] => 85
            [edition] => 6
            [name] => 8
            [type] => 2
        )

    [test6] => Array
        (
            [volume] => 67
            [edition] => 7
            [name] => 11
            [type] => 2
        )

)

You can add as many columns if you like. I hope this helps.

Edit: As to your question: No, Array MultiSort is NOT for sorting arrays based on a predefined order. What array_multisort does is: It Sorts an array by the given Condition (asc or desc) and moves entries in the other arrays relatively up or down, without violating the sorting of any other array.

basic example:

$letters = array("b","a","c");
$numbers = array(5,4,2);

calling array_multisort($letters,$numbers) will result in a,b,c and (a has moved up, b down) 4,5,2

if the example would be:

$letters = array("b","a","a");
$numbers = array(5,4,2);

first the same sorting will apply: (a,a,b -> 4,2,5), but then array_multisort notices, that it can swap the both as to sort 2 and 4. Final REsult: a,a,b -> 2,4,5

Back to your question:

To sort by a predefined order, you can do the following:

1.) Define your order, i.e. $order = array("a","z","b");

2.) Call uasort with a user function.

3.) Inside that sort function, use array flip and assoc access to get the actual position:

$items = array("a","b","z","a","z","z");

uasort($items, "sortByPredefinedOrder");

function sortByPredefinedOrder($leftItem, $rightItem){
  $order = array("a","z","b","x"); //defined somewhere

  $flipped = array_flip($order); //so we can access "position by value"

  $leftPos = $flipped[$leftItem];
  $rightPos = $flipped[$rightItem];
  return $leftPos >= $rightPos;   
}

print_r($items); //Array ( [0] => a [3] => a [2] => z [4] => z [5] => z [1] => b )

for your multidimensional Input, you can use

  $leftPos = $flipped[$leftItem["volume"]];
  $rightPos = $flipped[$rightItem["volume"]];

But ofc. this would require you to predict ALL values inside the predefined order Array and handle IndexOutOfBoundExceptions with appropriate return values.

Share:
10,675
Mark
Author by

Mark

Updated on June 13, 2022

Comments

  • Mark
    Mark almost 2 years

    I am trying to sort a multidimensional array using the array_multisort function

    I was expecting the multidimensional array to order itself using the values in $sort. $sort relates to the volume element of my multidimensional array.

    I would like the name element to be in this order:

    'name' => 8, 'name' => 6, 'name' => 7, 'name' => 9', 'name' => 10, 'name' => 10,

    The returned order is not as expected. Perhaps I have misunderstood how array_multisort works?

    Array
    (
    [test1] => Array
        (
            [volume] => 67
            [edition] => 2
            [name] => 6
            [num] => 2
        )
    
    [test2] => Array
        (
            [volume] => 86
            [edition] => 1
            [name] => 7
            [type] => 2
        )
    
    [test3] => Array
        (
            [volume] => 85
            [edition] => 6
            [name] => 8
            [type] => 2
        )
    
    [test4] => Array
        (
            [volume] => 98
            [edition] => 2
            [name] => 9
            [type] => 2
        )
    
    [test5] => Array
        (
            [volume] => 86
            [edition] => 6
            [name] => 10
            [type] => 2
        )
    
    [test6] => Array
        (
            [volume] => 67
            [edition] => 7
            [name] => 11
            [type] => 2
        )
    
    )
    
    $sort = array(85, 67, 86, 98, 86, 67);
    array_multisort($sort, $data);
    

    Here is the original array:

    $data['test1'] = array('volume' => 67, 'edition' => 2, 'name' => 6, 'num' => 2,);
    $data['test2'] = array('volume' => 86, 'edition' => 1, 'name' => 7, 'type' => 2,);
    $data['test3'] = array('volume' => 85, 'edition' => 6, 'name' => 8, 'type' => 2,);
    $data['test4'] = array('volume' => 98, 'edition' => 2, 'name' => 9, 'type' => 2,);
    $data['test5'] = array('volume' => 86, 'edition' => 6, 'name' => 10, 'type' => 2,);
    $data['test6'] = array('volume' => 67, 'edition' => 7, 'name' => 11, 'type' => 2,);