2

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,);
Mark
  • 778
  • 2
  • 11
  • 21
  • 1
    can you post the original array, and how you call the sort function? – dognose Jun 26 '13 at 16:08
  • Like @dognose said, if we don't know the original order of the array it's hard to say anything—but it seems to be working as expected. However, if you're just wanting to sort by the _name_ attribute, maybe you should use [uasort](http://www.php.net/manual/en/function.uasort.php) instead. – DaoWen Jun 26 '13 at 16:10
  • Have added the original array. – Mark Jun 26 '13 at 16:12
  • thx for adding the array - if you know say, WHAT Order you expect, we might be able to help you :) – dognose Jun 26 '13 at 16:12
  • 1
    @dognose - He did say this: *I was expecting the multidimensional array to order itself using the values in $sort so the name element would be in this order* – DaoWen Jun 26 '13 at 16:14
  • @DaoWen And what is `$sort`? – dognose Jun 26 '13 at 16:16
  • 1
    $sort is an array containing values from the volume element. Don't think I made that clear in my post. – Mark Jun 26 '13 at 16:24
  • 1
    See my answer. If `$sort` contains the volume elements, your call would look like `array_multisort($sort, SORT_ASC, $data)` – dognose Jun 26 '13 at 16:29
  • @dognose - I think you missed the fact that you can scroll down in his code / output snippet to see the defintion of `$sort` and the call to `array_multisort` at the very bottom. – DaoWen Jun 26 '13 at 16:57
  • @DaoWen dont missunderstand that - just overseen it :) – dognose Jun 26 '13 at 17:33

1 Answers1

10

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.

dognose
  • 20,360
  • 9
  • 61
  • 107
  • That's a really useful example, and one that I have bookmarked, but it's not quite what I wanted. I need to perform a custom sort based on values in my $sort array. I won't necessarily be able to order via ASC or DESC. – Mark Jun 26 '13 at 16:32
  • You can do this same thing with [uasort](http://www.php.net/manual/en/function.uasort.php), but without having to build all the extra arrays. – DaoWen Jun 26 '13 at 16:53
  • 1
    @monkey64 Added example for sorting with predefined order ... ehm... at the bottom of my answer :D – dognose Jun 26 '13 at 17:01
  • Your examples are quite excellent and easy to understand. I thank you for the time you spent on this and hope that it helps future visitors. – Mark Jun 26 '13 at 19:57