Сортировка гонщиков / игроков по местам

#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;
        }
    }
});