1

I have an array of names which I need to sort by

  1. lastname
  2. firstname
  3. mi

I can sort by one field (i.e. lastname) using usort

usort($name_apha, function($a, $b) {
   return $a['ln'] - $b['ln'];
});

But that only gets me 1/3 of the way.

Question: How can I sort all three fields (ln, fn them mi) to get the proper results? Below is an example of the data that needs sorting.

array (size=5)
  0 => 
    array (size=4)
      'ID' => int 425
      'ln' => string 'Bolware' (length=10)
      'fn' => string 'Christian' (length=9)
      'mi' => string '' (length=0)
  1 => 
    array (size=4)
      'ID' => int 423
      'ln' => string 'Bernstein' (length=9)
      'fn' => string 'Bear' (length=5)
      'mi' => string 'D.' (length=2)
  2 => 
    array (size=4)
      'ID' => int 419
      'ln' => string 'Bellweather' (length=7)
      'fn' => string 'Brent' (length=9)
      'mi' => string '' (length=0)
  3 => 
    array (size=4)
      'ID' => int 356
      'ln' => string 'Bayleaf, III' (length=13)
      'fn' => string 'Joe' (length=5)
      'mi' => string 'X.' (length=2)
  4 => 
    array (size=4)
      'ID' => int 336
      'ln' => string 'Public' (length=6)
      'fn' => string 'John' (length=4)
      'mi' => string 'Q.' (length=2)
4
  • It is not perfect, but you could sort three consecutive times, first with the less important field (mi), then the second one (fn) and lastly the most important (ln). Commented Dec 20, 2014 at 22:36
  • Not sure why do you have length in there? Do you want a lexicographic sort (alphabetic) with first field being most important, then second etc? Commented Dec 20, 2014 at 22:37
  • 1
    If I search Stack Overflow for the title of this post, I get a lot of results that look very similar to your situation. Are you sure none of them already answers your question? Commented Dec 20, 2014 at 22:38
  • @Paul Crovella good to know. Will do from now on. Commented Dec 20, 2014 at 22:42

2 Answers 2

4

First, don't use subtraction to compare strings; use strcmp (or strcasecmp for case-insensitive comparison).

To compare on all three values, you can use a cascade with the ternary operator ? :, like this:

usort($name_alpha, function($a, $b) {
    return strcmp($a['ln'], $b['ln']) // will return this if it is not 0
        ?
        : strcmp($a['fn'], $b['fn']) // will return this if it is not 0
            ?
            : strcmp($a['mi'], $b['mi']);  // will return this if it made it this far
});

DEMO

The complete code looks like this:

$name_alpha = array (
    0 =>
        array (
            'ID' => 425,
            'ln' => 'Bolware',
            'fn' => 'Christian',
            'mi' => '',
        ),
    1 =>
        array (
            'ID' => 423,
            'ln' => 'Bernstein',
            'fn' => 'Bear',
            'mi' => 'D.',
        ),
    2 =>
        array (
            'ID' => 419,
            'ln' => 'Bellweather',
            'fn' => 'Brent',
            'mi' => '',
        ),
    3 =>
        array (
            'ID' => 356,
            'ln' => 'Bayleaf, III',
            'fn' => 'Joe',
            'mi' => 'X.',
        ),
    4 =>
        array (
            'ID' => 336,
            'ln' => 'Public',
            'fn' => 'John',
            'mi' => 'Q.',
        )
);

usort($name_alpha, function($a, $b) {
    return strcmp($a['ln'], $b['ln']) // will return this if it is not 0
        ?
        : strcmp($a['fn'], $b['fn']) // will return this if it is not 0
            ?
            : strcmp($a['mi'], $b['mi']);  // will return this if it made it this far
});

print_r($name_alpha);

The output is:

Array
(
    [0] => Array
        (
            [ID] => 356
            [ln] => Bayleaf, III
            [fn] => Joe
            [mi] => X.
        )
    [1] => Array
        (
            [ID] => 419
            [ln] => Bellweather
            [fn] => Brent
            [mi] => 
        )
    [2] => Array
        (
            [ID] => 423
            [ln] => Bernstein
            [fn] => Bear
            [mi] => D.
        )
    [3] => Array
        (
            [ID] => 425
            [ln] => Bolware
            [fn] => Christian
            [mi] => 
        )
    [4] => Array
        (
            [ID] => 336
            [ln] => Public
            [fn] => John
            [mi] => Q.
        )
)
Sign up to request clarification or add additional context in comments.

Comments

0

Why not just concatenate the three fields in the comparison? I.e.:

return ($a['ln'] . $a['fn'] . $a['mi']) - ($b['ln'] . $b['fn'] . $b['mi']);

That would return the correct sort including ties on ln or ln+fn.

1 Comment

This doesn't work. Simply because you compare strings with subtraction.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.