mr_ed
mr_ed

Reputation: 21

Sort strings by trailing numeric substring (naturally), then by leading alphabetic substring

I have an array of strings which are consistently formatted as a letter followed by a number. I need to sort them by number first then by letter.

Sample input:

$data = [
    'A1',
    'A2',
    'A5',
    'A10',
    'B2',
    'B4',
    'C10',
    'B5',
    'C1',
    'B1',
    'C2',
];

I need the following result:

[
    'A1',
    'B1',
    'C1',
    'A2',
    'B2',
    'C2',
    'B4',
    'A5',
    'B5',
    'A10',
    'C10',
]

Upvotes: 0

Views: 1381

Answers (3)

mickmackusa
mickmackusa

Reputation: 47900

Use array_multisort() to sort on two rules, first remove the non-digital characters and sort by integer value, then sort normally by the leading string.

Code: (Demo)

array_multisort(preg_replace('/\D+/', '', $data), SORT_NUMERIC, $data);

Upvotes: 1

sevavietl
sevavietl

Reputation: 3812

Not the most efficient, but quite laconic approach will be to use array_multisort and array_map:

array_multisort(
    array_map(function ($item) { return substr($item, 1); },$array),
    array_map(function ($item) { return $item[0]; },$array),
    $array
);

Here is working demo.

Upvotes: 0

Mark Baker
Mark Baker

Reputation: 212412

usort() allows you to create a custom sort rule, so you can create a rule that splits the value into letters and digits, and compare those

usort(
    $data,
    function($a, $b) {
        sscanf($a, '%[A-Z]%d', $ac, $ar);
        sscanf($b, '%[A-Z]%d', $bc, $br);
        return ($ar == $br) ? $ac <=> $bc : $ar <=> $br;
    }
);

Demo

Upvotes: 2

Related Questions