Как объединить несколько функций сортировки - PullRequest
0 голосов
/ 11 февраля 2020

Это работает как шарм в SQL:

SELECT * FROM person ORDER BY age DESC, name ASC

Но что, если у нас есть такие данные в массиве PHP. Как мы можем сделать то же самое? Например, если у меня есть

$a = [
['name' => 'Alfred', 'age' => 40],
['name' => 'Mark', 'age' => 40],
['name' => 'Lue', 'age' => 45],
['name' => 'Ameli', 'age' => 38],
['name' => 'Barb', 'age' => 38],
];

, и я хочу отсортировать его по возрасту в порядке убывания, а затем по имени в порядке возрастания. Так же, как в SQL выше. Итак, правильная последовательность имен: Lue, Alfred, Mark, Ameli, Barb. См. db-fiddle .

неверная попытка получить его в PHP:

usort($array, function ($a, $b) {
    return -strnatcasecmp($a['age'], $b['age']); // desc
});

usort($array, function ($a, $b) {
    return strnatcasecmp($a['name'], $b['name']); // asc
});

Каждый из двух вызовов usort работает хорошо, но это отменяет предыдущий результат, хотя я хочу объединить их все вместе. В идеале я хотел бы иметь функцию, которая принимает любое количество Callable, чтобы сортировать их всех.

Пожалуйста, сообщите.

Обновление : Как разумно прокомментировано ниже, array_multisort подходит для сортировки регулярного массива, подобного этому. Но я бы хотел найти решение для объединения comparator closures. ЛЮБЫЕ компараторы, даже как этот .
Кстати, SQL позволяет сортировать по выражению, а не только по простому полю.

Ответы [ 2 ]

1 голос
/ 11 февраля 2020

Вот способ сделать это:

function combineComparators(...$comparators)
{
    return function($a, $b) use($comparators)
    {
        foreach($comparators as $c)
        {
            $res = $c($a, $b);
            if($res!=0)
                return $res;
        }
        return 0;
    };
}

$a = [
['name' => 'Alfred', 'age' => 40],
['name' => 'Mark', 'age' => 40],
['name' => 'Lue', 'age' => 45],
['name' => 'Ameli', 'age' => 38],
['name' => 'Barb', 'age' => 38],
];

$cmp1 = function ($a, $b) {
    return -strnatcasecmp($a['age'], $b['age']); // desc
};

$cmp2 = function ($a, $b) {
    return strnatcasecmp($a['name'], $b['name']); // asc
};

usort($a, combineComparators($cmp1, $cmp2));

var_dump($a);
1 голос
/ 11 февраля 2020

У кого-нибудь будет хороший usort, но я предпочитаю array_multisort.

Извлечь каждый столбец, отсортировать по ним по порядку, а затем отсортировать оригинал по порядку сортировки:

array_multisort(array_column($a, 'age'), SORT_DESC, array_column($a, 'name'), SORT_ASC, $a);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...