Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm trying to sort a multi-dimensional array by another array, but have so far come up short.
array_multisort seems be working only for real sorting.

Suppose I have these 2 arrays:

$order = array(2,3,1);

$data = array(
    array('id' => 1, 'title' => 'whatever'),
    array('id' => 2, 'title' => 'whatever'),
    array('id' => 3, 'title' => 'whatever')
);

Now I would like to sort my $data array according to the order in my $order array.
This is what I would like the result to be:

$data = array(
    array('id' => 2, 'title' => 'whatever'),
    array('id' => 3, 'title' => 'whatever')
    array('id' => 1, 'title' => 'whatever'),
);

I can accomplish this easily by running a nested loop, but that would not scale well (my array is pretty big, and the arrays have many more fields).

share|improve this question

3 Answers

up vote 2 down vote accepted

There is no built-in function for this in PHP and i am unable to think of any custom function, which would do this using usort. But array_map is simple enough, imo, so why not use it instead?

$sorted = array_map(function($v) use ($data) {
    return $data[$v - 1];
}, $order);
share|improve this answer
im not able to use anonymous functions with my current version of php - how would this work without using them? – Gaz_Edge Nov 27 '12 at 17:17
have opened a question here stackoverflow.com/questions/13589707/… – Gaz_Edge Nov 27 '12 at 17:40

In your example the ids in the $data array are are numbered consecutively and starting at 1. The code I give below assumes this is always the case. If this is not the case, the code does not work.

$result = array();
$index = 0;
foreach ($order as $position) {
    $result[$index] = $data[$position - 1];
    $index++;
}

At http://codepad.org/YC8w0yHh you can see that it works for your example data.

EDIT

If the assumption mentioned above does not hold, the following code will achieve the same result:

<?php

$data = array(
    array('id' => 1, 'title' => 'whatever'),
    array('id' => 2, 'title' => 'whatever'),
    array('id' => 3, 'title' => 'whatever')
);

$order = array(2,3,1);
$order = array_flip($order);

function cmp($a, $b)
{
    global $order;

    $posA = $order[$a['id']];
    $posB = $order[$b['id']];

    if ($posA == $posB) {
        return 0;
    }
    return ($posA < $posB) ? -1 : 1;
}

usort($data, 'cmp');

var_dump($data);

See http://codepad.org/Q7EcTSfs for proof.

By calling array_flip() on the $order array it can be used for position lookup. This is like a hashtable lookup, which is linear in time, or O(n). You cannot do better.

share|improve this answer
Your last solution is basically running a sugared nested loop. I don't think that would scale well. – MegaHit Oct 19 '11 at 0:01
@MegaHit see updated code in my answer, you cannot do better than that. – Jan-Henk Oct 19 '11 at 10:09

You could try using a custom sort with usort(). This way you can use the first array to determine the order of the second array.

share|improve this answer
I had looked at usort, but a don't know if/how it works with multi-dimensional arrays. – MegaHit Oct 18 '11 at 22:25
That's what makes it so useful. You define a function which has access to the entire item whether it's just a string or a multidimensional array. So in the comparison function you could compare each values index in the order array. So something like this: return (array_search($a['id'], $order) > array_search($b['id'], $order)) ? -1 : 1; – Justin Lucas Oct 18 '11 at 22:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.