Using usort(), is it possible to sort strings that also contain integer values?

For example, take this array of objects containing email addresses (and other data) -

$invitees = Array(
    [0] => Array(
        'email' => 'test11@testing.com'
    ),
    [1] => Array(
        'email' => 'test2@testing.com'
    ),
    [2] => Array(
        'email' => 'test1@testing.com'
    )
);

Using the following code compares the array elements as just a simple string -

/** Sort the data (if the sort key is defined) */
if(!empty($_REQUEST['orderby'])) :
    usort($emails, array(&$this, '_order_callback'));
endif;

function _order_callback($item_a, $item_b){

    /** Grab 'orderby', which must have been set for this function to be called */
    $orderby = $_REQUEST['orderby'];

    /** If no 'order' is not set, default to ASC */
    $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'ASC';

    $result = strcmp($item_a[$orderby], $item_b[$orderby]);

    return (strtoupper($order) === 'ASC') ? $result : -$result; //Send final sort direction to usort

}

The results are delivered in the following order -

[0] - 'test11@testing.com'
[2] - 'test1@testing.com'
[1] - 'test2@testing.com'

Where as I desire this order -

[2] - 'test1@testing.com'
[1] - 'test2@testing.com'
[0] - 'test11@testing.com'

Is this possible with usort()? Thanks.


Edit

Now that I know of the existence of natsort() (thanks to the below comments/answers), I was able to find and try this -

$result = ($item_a[$orderby] > $item_b[$orderby] ? 1 : ($item_a[$orderby] < $item_b[$orderby] ? -1 : 0));

I added that comparison to my _order_callback() function (if $orderby === email), and it's close, but sorts in the order 11, 12, 13, 14, 1, 2, 3, 4.

有帮助吗?

解决方案

Use strnatcmp() to do the comparison in your usort() callback

$email1 = new StdClass;
$email1->email = 'test11@testing.com';
$email2 = new StdClass;
$email2->email = 'test1@testing.com';
$email3 = new StdClass;
$email3->email = 'test2@testing.com';
$email4 = new StdClass;
$email4->email = 'test12@testing.com';
$email5 = new StdClass;
$email5->email = 'test21@testing.com';
$email6 = new StdClass;
$email6->email = 'test3@testing.com';

$invitees = array(
    $email1,
    $email2,
    $email3,
    $email4,
    $email5,
    $email6,
);


usort($invitees, '_order_callback');

function _order_callback($item_a, $item_b){
    return strnatcmp($item_a->email, $item_b->email);
}

var_dump($invitees);

其他提示

As Mark Baker says, natsort is what you are looking for.

$emails = array(
    'test2@testing.com',
    'test11@testing.com',
    'test1@testing.com'
);

natsort( $emails );

Thanks to @MarkBaker, @MajorCaiger and @hdvianna, here is the final order callback function that I am using.

This function takes in to account multiple sort criteria from a multi-dimensional array.

/** Sort the data (if the sort key is defined) */
if(!empty($_REQUEST['orderby'])) :
    usort($invitees[$status], array(&$this, '_order_callback'));
endif;

/**
 * Callback function to order event invitees
 *
function _order_callback($item_a, $item_b){

    /** Grab 'orderby', which must have been set for this function to be called */
    $orderby = $_REQUEST['orderby'];

    /** If no 'order' is not set, default to ASC */
    $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'ASC';

    switch($orderby) :

        case 'ID' : // ID is unique, so just sort by ID
            $result = strnatcmp($item_a[$orderby], $item_b[$orderby]);
            break;

        case 'email' :
            $result = strnatcasecmp($item_a[$orderby], $item_b[$orderby]);
            if($result === 0) :
                $result = strcmp($item_a['first_name'], $item_b['first_name']);
            endif;
            if($result === 0) :
                $result = strcmp($item_a['surname'], $item_b['surname']);
            endif;
            break;

        case 'name' :
            $result = strcmp($item_a['first_name'], $item_b['first_name']); // Explicitly declare 'first_name' here as $orderby is actuualy 'name', which is a constructed field for display
            if($result === 0) :
                $result = strcmp($item_a['surname'], $item_b['surname']);
            endif;
            if($result === 0) :
                $result = strnatcasecmp($item_a['email'], $item_b['email']);
            endif;
            break;

        default : // 'custom' and 'town'
            $result = strcmp($item_a[$orderby], $item_b[$orderby]);
            break;

    endswitch;

    return (strtoupper($order) === 'ASC') ? $result : -$result; //Send final sort direction to usort

}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top