Mike.Linford
Mike.Linford

Reputation: 95

PHP - Sorting an Associative array by another array's values

I have two arrays, one is a multidimensional array which holds information, the other is a simple array which holds values for the order I want the first array in.

For example, I want my first array to be ordered by ID, by the values in the second array.

$users array:

array(3) {
    [0] => array(3) {
            'id' => 1,
            'name' => 'John Smith',
            'email' => '[email protected]',
        },
    [2] => array(3) {
            'id' => 2,
            'name' => 'Jane Smith',
            'email' => '[email protected]',
        },
    [0] => array(3) {
            'id' => 3,
            'name' => 'Jack Smith',
            'email' => '[email protected]',
        },
}

$order array:

array(3) {
    [0] => '2',
    [1] => '3',
    [2] => '1',
}

What I would like the outcome of the sorted array to be:

array(3) {
    [0] => array(3) {
            'id' => 2,
            'name' => 'Jane Smith',
            'email' => '[email protected]',
        },
    [2] => array(3) {
            'id' => 3,
            'name' => 'Jack Smith',
            'email' => '[email protected]',
        },
    [0] => array(3) {
            'id' => 1,
            'name' => 'John Smith',
            'email' => '[email protected]',
        },
}

So as you can see, I would like the array keys to be reindexed, so they are always sequential starting from 0, but for the values of each element in the $users array to be re ordered.

Upvotes: 2

Views: 3386

Answers (3)

Yacine al
Yacine al

Reputation: 173

You can use usort to achieve this :

        // the key order of each id
        $orderIdKeys  = array_flip($order);

        usort($users, function ($u1, $u2)  use ($orderIdKeys) {

            // compare the keys of the ids in the $order array
            return $orderIdKeys[$u1['id']] >= $orderIdKeys[$u2['id']] ?  1 : -1;
        });

Then $users should be ordered.

The usort here is comparing users based on the position ( which is $orderIdKeys[$u1['id']] ) of each user id in $order array, If the position of $u1['id'] is greater than the position of $u2['id'] the callback returns 1 which means $u2 should be placed before $u1 in the final ordered array

Upvotes: 1

sevavietl
sevavietl

Reputation: 3802

You can do this like this:

// Index users by ID
$users = array_combine(
    array_column($users, 'id'),
    $users
);

// Order the users
$users = array_map(function ($id) use ($users) {
    return $users[$id];
}, $order);

Here I used array_combine() function, that creates array by mapping given keys to values. For the keys I used all the id's in a sequential order (grabbed them with array_column()).

Having an array in such form, I can loop over $order array and grab the values from $users array by index, that actually have the value of id now.

Instead of looping with foreach I used array_map() function. If you have a collection (i.e. array) it is better to use higher order functions to process them. If you are a beginner it can be overwhelming, but you have to learn this, as this is the way things done nowadays.

Here is working example.

Upvotes: 5

Samuil Banti
Samuil Banti

Reputation: 1795

I think that this should do the job:

$array = array(
    array(
            'id' => 2,
            'name' => 'Jane Smith',
            'email' => '[email protected]',
    ),
    array(
            'id' => 3,
            'name' => 'Jack Smith',
            'email' => '[email protected]',
    ),
    array(
            'id' => 1,
            'name' => 'John Smith',
            'email' => '[email protected]',
    ),
);

function cmp_by_optionNumber($a, $b) {
  return $a["id"] - $b["id"];
}
usort($array, "cmp_by_optionNumber");

var_dump($array);

It will sort your main array by the values of the "id" keys in the subarrays.

Upvotes: -1

Related Questions