#php #algorithm #sorting
#php #алгоритм #сортировка
Вопрос:
У меня есть данные о некоторых гонщиках, представленные в следующей форме:
массив( массив (имя => "первый гонщик", места => [1,3,1,5,6,2,6,7,8]), массив(имя => "второй гонщик", места => [2,4,2,5,7]) ... )
Посоветуйте лучший способ их сортировки, чтобы первыми были гонщики, у которых места получше. Например, если у первого гонщика есть хотя бы одно первое место, а у другого нет, то первый находится выше в списке. Если у них обоих первые места, сравните количество первых мест. Если число тоже равно, сравните вторые места и так далее.
Мое решение (оно выглядит не очень элегантно. Может быть, это можно сделать как-то проще):
$racers = массив( массив('имя' => "первый гонщик", 'места' => [1,3,1,5,6,2,6,7,8,9]), массив('имя' => "второй гонщик", 'места' => [1,3,1,5,6,2,6,7,8]), массив('имя' => "третий гонщик", 'места' => [2,3,2,5,7,10]), массив('имя' => "четвертый гонщик", 'места' => [2,3,10,6,6,10]), массив('name' => "пятый", 'places' => [2,3,2,5,7,10,1]), ); usort($racers, функция($prev, $ next) { // упорядочить места для каждого гонщика сортировать($prev['места']); сортировать($next['места']); //сравните каждое место друг с другом foreach ($prev['places'] КАК $key => $prevRacerPlace) { // если все значения равны, мы сравниваем количество гонок if (!isset($next['места'][$ключ])) { возвращает -1; } $nextRacerPlace = $next['места'][$ключ]; $diff = $prevRacerPlace - $nextRacerPlace; если ($diff !== 0) { возвращает $diff; } } // если все значения равны, мы сравниваем количество гонок if (count($next['места']) > count($prev['места'])) { возвращает 1; } }); var_dump($racers);
Комментарии:
1. Вы должны хотя бы попытаться решить это самостоятельно..
2. @Darren, я пытался, но мне не нравится моя версия. Это очень громоздко. Я добавил это в описание.
3. Возможно, было бы проще, если бы вы поместили данные в формат, который вам удобнее использовать, например, этот ..
4. @Darren Это своего рода
array_count_values()
, но это делает алгоритм еще более сложным. Это вообще не требуется.
Ответ №1:
Было бы неплохо сделать некоторые приготовления перед пользовательской сортировкой. Таким образом, мы избегаем вложенных сортировок в лямбда-функции:
foreach ($racers as $index => $racer) {
$racers[$index]['sorted_places'] = $racer['places'];
sort($racers[$index]['sorted_places']);
}
В сортирующей лямбда-функции мы сравниваем заголовки подготовленных отсортированных мест и возвращаем первое определенное значение. Если результат гонщика, занявшего первое место B, лучше, чем результат A, верните 1. Если результат гонщика, занявшего первое место A, лучше, чем результат B, верните значение -1. При равных результатах продолжайте проверку следующих лучших мест.
usort($racers, function ($a, $b) {
unset($value);
do {
$topA = array_shift($a['sorted_places']);
$topB = array_shift($b['sorted_places']);
if (is_null($topA) amp;amp; is_null($topB)) {
$value = 0;
} elseif (is_null($topA)) {
$value = 1;
} elseif (is_null($topB)) {
$value = -1;
} elseif ($topA > $topB) {
$value = 1;
} elseif ($topA < $topB) {
$value = -1;
}
} while (!isset($value));
return $value;
});
Ответ №2:
Вот еще один алгоритм, но я думаю, что решение Макса Зубера более эффективно. В любом случае:
Определите, сколько мест было для каждого гонщика с помощью array_count_values
foreach ($racers as amp;$racer) {
$racer['number_places'] = array_count_values($racer['places']);
}
и сортировка
usort($racers, function($current, $next) {
$next_places = $next['number_places'];
$current_places = $current['number_places'];
for ($i=1; $i<=max($next_places, $current_places); $i ) {
if (!isset($current_places[$i]) amp;amp; !isset($next_places[$i])) {
continue;
}
if (!isset($current_places[$i])) {
return 1;
}
if (!isset($current_places[$i])
|| $current_places[$i] > $next_places[$i])
{
return -1;
}
}
});