0

I have a list of ids [1,500,7] and a list of entities with corresponding id properties, but in a different order (1 -> 7, 500). In php, how can I sort them according to the list of ids?

Php version is 5.3.2

2
  • Can you give us a sample of the actual data? Commented Sep 9, 2011 at 13:58
  • If you don't share a list of those entities how can we help you? If you want us to help, be reasonable, share some code we can look at and work with. Commented Sep 9, 2011 at 13:59

3 Answers 3

4

Given some data structures like the following (from your description):

$ids = array(5, 15, 10);
$values = array(
  (object) array('id' => 10, 'data' => 'foo'),
  (object) array('id' => 5, 'data' => 'foo'),
  (object) array('id' => 15, 'data' => 'foo'),
);

You could use something like the following:

// Precalculate sort positions to avoid two calls to array_search for each sort
// operation as that gets costly very quickly.
$id_positions = array_flip($ids);
// Do the actual sorting here.
usort($values, function($a, $b) use ($id_positions) {
  return ($id_positions[$a->id] < $id_positions[$b->id] ? -1 : 1);
});

The above code makes a few assumptions, but should get you on your way.

Sign up to request clarification or add additional context in comments.

7 Comments

All I would add to this is that you ought to decide what to do when $aPosition and bPosition are identical, which can happen. In this example, it will be as if $aPosition "won".
@Sohnee: Like I said, there's a few assumptions here. Depending on your data and where it's coming from, that may never happen. id implies some level of uniqueness in the data.
@Jan: If you need to support PHP < 5.3 then simply factor out the closure to a callback. If not, then enjoy the new 5.3 goodness.
Be aware that you end up doing 2 array searches every time 2 members of $values are compared. You might want to memoize the results of your array_search calls, if $values gets large
@Matthew Scharley: just to let you know, I realize that this is a demonstration of principle, and a solid one at that. However, if the OP decides to implement it, then handling that double array_search may become important.
|
0

You can create a compare function (or method inside a class) that should return a positive, negative or 0 value depending if the first value to compare is greater, lesser or equal to the second value. And then call usort() (in this link you'll find more info about the compare function).

2 Comments

Hm, that's quite unsatisfying. I would rather map over ids and attach the object with the right id as value. But maybe that's a too functional approach for php...
@Jan: PHP has only just started to push into the more functional side of programming. For instance, we only got closures in 5.3. Many of the functional functions are long-winded, and trying to chain them is a pain (you have to do it in reverse because there's no objects, just function calls). All in all, PHP isn't well suited to functional programming (yet, at least. I have hopes for PHP 6+).
0

Assuming that the list of IDs and the list of entities are the same length and that every ID has a corresponding entity and that every entity's ID is in the ID list.

$sorted_entities = array();
$sort_order = array_combine($list_of_ids, range(0, count($list_of_ids) - 1));
foreach ($list_of_entities as $entity) {
    $sorted_entities[$sort_order[$entity->id]] = $entity;
}

This has the advantage of traversing each array only once. It has the disadvantage that it does not sort the entities in place.

1 Comment

@Matthew Scharley's version is a much neater version of the above code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.