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

An array arrives with some or all of the following values, in any order. What's the best way to order them in ascending size order? So starting with small and ending with XXL. I can usort but am a bit lost as to how the elements should be ordered in my user defined function

Small
XXL
Medium
Large 
XL

EDIT: left out some info so created new question http://stackoverflow.com/questions/4014743/custom-ordering-array-with-key-value-pairs

EDIT2: Full code

print_r($sizes);
$sorted_sizes = $this->sort_sizes(array_unique($sizes));
print_r($sorted_sizes);

function sort_sizes($sizes)
{
    return uasort($sizes, array($this, 'cmp'));
}

function cmp($a,$b)
{
    $sizeArray = array( 'Small' => 0, 'Medium' => 1, 'Large' => 2, 'XL' => 3, 'XXL' => 4); 
    return $sizeArray[$a] - $sizeArray[$b];
}

This outputs:

Array
(
    [66-507cddcd16d9786abafccfa78b19acf8] => XL
    [64-507cddcd16d9786abafccfa78b19acf8] => medium
    [65-507cddcd16d9786abafccfa78b19acf8] => large
    [63-507cddcd16d9786abafccfa78b19acf8] => small
)

and print_r($sorted_sizes) just gives output "1"

share|improve this question

3 Answers

up vote 4 down vote accepted

Updated answer according to full code

The first issue here is that you're returning the result of uasort():

function sort_sizes($sizes)
{
    return uasort($sizes, array($this, 'cmp'));
}

That's wrong, because uasort() does not return the sorted array. It modifies the same variable that you pass as a parameter, and returns a boolean value. That's why you see 1 as output.

Make the method accept $sizes by reference:

function sort_sizes(array &$sizes)
{
    uasort($sizes, array($this, 'cmp'));
}

Then call it like so:

print_r($sizes);
$sorted_sizes = array_unique($sizes);
$this->sort_sizes($sorted_sizes);
print_r($sorted_sizes);

Here's your cmp() method, with added support for case-insensitive sorting:

function cmp($a, $b)
{
    $sizes = array('small' => 0, 'medium' => 1, 'large' => 2, 'xl' => 3, 'xxl' => 4);
    return $sizes[strtolower($a)] - $sizes[strtolower($b)];
}

Old answer

Try this. Use uasort() instead if you want to maintain key-value pairs:

function sort_sizes($a, $b) {
    // Map the sizes to an ordered sequence of ints
    static $sizes = array('small' => 0, 'medium' => 1, 'large' => 2, 'xl' => 3, 'xxl' => 4);

    // Find the difference, using the sizes as keys to the above array
    return $sizes[strtolower($a)] - $sizes[strtolower($b)];
}

$arr = array('Small', 'XXL', 'Medium', 'Large', 'XL');

print_r($arr); // Before sorting
uasort($arr, 'sort_sizes');
print_r($arr); // After sorting

Output:

Array
(
    [0] => Small
    [1] => XXL
    [2] => Medium
    [3] => Large
    [4] => XL
)
Array
(
    [0] => Small
    [2] => Medium
    [3] => Large
    [4] => XL
    [1] => XXL
)
share|improve this answer
 
In case of an associate array you might want to use uasort. An example: ideone.com/FjxgY –  codaddict Oct 25 '10 at 12:50
 
How do I call sort_sizes in usort($arr, 'sort_sizes'); if these are methods in a class? Usually I call a function via $this->sort_sizes but if I pass that as an unquoted parameter I get a Undefined property: Products::$sort_sizes_do error. –  stef Oct 25 '10 at 12:51
 
@stef: Instead of usort($arr, 'sort_sizes');, do usort($arr, array($this, 'sort_sizes')); –  BoltClock's a Unicorn Oct 25 '10 at 12:53
 
Ok great. I'm making a second question since the input array actually has key/value pairs and the relation between the two needs to be maintained. stackoverflow.com/questions/4014743/… –  stef Oct 25 '10 at 12:59
 
@stef: codaddict's comment already answers that question: use uasort() instead of usort(). –  BoltClock's a Unicorn Oct 25 '10 at 13:00
show 5 more comments

You can do this using array_multisort:

$orderIndex = array_flip(array('Small','Medium','Large','XL','XXL'));
$arr = array('Small','XXL','Medium','Large','XL');
array_multisort(array_map(function($val) use ($orderIndex) { return $orderIndex[$val]; }, $arr), $arr);

Here array_map is used with an anonymous function to build an array of the “weight” of each value in $arr. That array is then used to order the values in $arr.

This is basically the same as BoltClock suggested just with doing the comparison on the already calculated “weights”.

share|improve this answer

Do the sorting in two phases. First, convert text to a convenient numeric value. In this moment you should decide if "L" and "Large" map to the same value or not. Then reorder the array based on those numeric conversions.

share|improve this answer

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.