1
votes

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)
2
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). - delCano
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? - MeLight
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? - IMSoP
@Paul Crovella good to know. Will do from now on. - sleeper

2 Answers

4
votes

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.
        )
)
0
votes

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.