Reorder array items to best match 'priority' order

Hi,

If I have an Array but I need to reorder it placing items the items that match the ‘priority’ items in the appropriate place. I am not concerned with the order of items that do not match.

The priority list could be stored in an array but doesn’t have to be.


// priority
// massive = 1st
// big = 2nd

$sizes = array("other size", "big", "massive", "another size");

// required output

$sizes = array("massive", "big", "other size", "another size");


I can find examples of reordering according to value. Do I need to chance the array - assigning each item a priority ‘value’ first? I’m not sure how if this is required or how to do this.


$sizes = array("other size", "big", "massive", "another size");

$priorities = array('big', 'massive'); // need to be in reverse priority order! (left as an exercise to the reader)

foreach ($priorities as $priority)
{
    if (($key = array_search($priority, $sizes)) !== false)
    {
        unset($sizes[$key]);
        array_unshift($sizes, $priority);
    }
}

var_dump($sizes);

// array (size=4)
//   0 => string 'massive' (length=7)
//   1 => string 'big' (length=3)
//   2 => string 'other size' (length=10)
//   3 => string 'another size' (length=12)

All other sizes remain in their original order

Unless I’m misreading the question, there’s really no need for looping or anything particularly complicated.


$sizes = array("other size", "big", "massive", "another size");
$priorities = array("massive", "big");
$result = array_merge(array_intersect($priorities, $sizes), array_diff($sizes, $priorities));

I’m sure we can detail what is happening if you’re at all unsure. (:

Thank you both.

ScallioXTX - I think I understand your response though I haven’t tried it. I tfind it interesting as I thought I might be able to use a For loop but had assumed it would have been on the Sizes Array rather than the Priorities Array.

Salathe - You solution works perfectly. Though I have no idea what is going on! Would you mind explaining?

Your best shot is to use PHP’s splpriorityqueue class, it does what you need.

Salathe’s solution works on a couple of the quirks (if you want to call them that) or methods of how array_intersect and array_diff work (moreso the former).

Array_Intersect takes multiple arguments in the form of arrays; It then intersects each array in turn with the initial array, to give a result array. Due to the way this function works, it will always check the first item of the array first (as defined by an array-shift; not by key value. Think of it like doing a FOREACH on the array), then the second. Thus by defining “massive” as the first element of the match-against array, you effectively prioritize it in the array_intersect, because it will search for “massive” first, then “big”. It’s an iterative construction. Note that you would NOT have gotten the same result if you’d array_intersected with the parameters the other way around!

Array_diff does the same thing but in reverse; it finds everything that is in the initial array that isnt in the secondary. Again, order (and keys) is preserved; so the ‘remainder’ remains in the same order as when it went in (and missing any keys for which it had a deleted value) because of the order in which the parameters are given. The secondary (‘input’) array is first in the parameter list, so it defines the order of the output.

So now you have two complimentary arrays (the intersected, or matched values, in order of the $priorities, and the diffed, or unmatched, in the original order).

Array_merge takes the second array, plops it on the end of the first array. In this way you have prioritized the values you wanted to prioritize, in the order you wanted to prioritize them; the rest of the data you didnt care about, so it’s just stuck on the end, unsorted.

If this is still unclear let me know.

Thanks for the explanation, StarLion. It saves me typing one.

That said, I wouldn’t at all say that I was using “quirks” of those functions (I’m not misusing them, or even using them in a useful way for which they were not intended); simply, “using the standard library effectively.” (:

Did you read the word “priority” and decided to chip in? Not that the SplPriorityQueue wouldn’t be able to do the job, but it would be a strange choice.

Nope, I did read the topic carefully before posting my response so it’s not like I recommended using priority queue without a reason. PHP built-in arrays are bad practices and not even object oriented, in my application I use splfixedarray(or more precisely a subclass of splfixedarray) for arrays, it’s even faster than PHP’s built in arrays. That’s for numerically indexed arrays, associative arrays really should’ve been objects to begin with so I pretty much never use it.

In fact, for the OP’s application I’d say extending splpriorityqueue to provide a custom compare method that overrides splpriorityqueue’s compare method will work out the best. I have my own priority queue class too, but it’s different from splpriorityqueue in a way that it’s compare method is delegated to comparator classes so that instead of subclassing priority queue class, you simply provide different comparator class to decide how priority is calculated and compared. I personally like this approach better than splpriorityqueue’s, but it’s a matter of choice.