按地点排序赛车手/球员

时间:2016-10-23 23:04:12

标签: php algorithm sorting

我有一些以下列形式呈现的赛车手的数据:

    array(
        array(name => "the first racer", places => [1,3,1,5,6,2,6,7,8]),
        array(name => "the second racer", places => [2,4,2,5,7])
        ... 
    )

建议对它们进行排序的最佳方法,以便第一批参赛选手有更好的位置。例如,如果第一个赛车至少有一个第一名而另一个没有,则第一个在列表中更高。如果他们都有第一名,请比较第一名的数量。如果数字相等,则比较第二个位置,依此类推。

我的解决方案(它看起来不太优雅。也许它可以以某种方式更轻松地完成):


    $racers = array(
        array('name' => "the first racer", 'places' => [1,3,1,5,6,2,6,7,8,9]),
        array('name' => "the second racer", 'places' => [1,3,1,5,6,2,6,7,8]),
        array('name' => "the third racer", 'places' => [2,3,2,5,7,10]),
        array('name' => "the fourth racer", 'places' => [2,3,10,6,6,10]),
        array('name' => "the fifth", 'places' => [2,3,2,5,7,10,1]),
    );

    usort($racers, function($prev, $next) {
        // order places for every racer
        sort($prev['places']);
        sort($next['places']);

        //compare each place with each other 
        foreach ($prev['places'] AS $key => $prevRacerPlace) {
            // if all values are equal, we compare the number of races
            if (!isset($next['places'][$key])) {
                return -1;
            }
            $nextRacerPlace = $next['places'][$key];
            $diff = $prevRacerPlace - $nextRacerPlace;
            if ($diff !== 0) {
                return $diff;
            }
        }
        // if all values are equal, we compare the number of races
        if (count($next['places']) > count($prev['places'])) {
            return 1;
        }
    });

    var_dump($racers);

2 个答案:

答案 0 :(得分:3)

在自定义排序之前做一些准备工作会很不错。所以我们避免在lambda函数中嵌套排序:

foreach ($racers as $index => $racer) {
    $racers[$index]['sorted_places'] = $racer['places'];
    sort($racers[$index]['sorted_places']);
}

在对lambda函数进行排序时,我们比较准备好的排序位置的头部并返回第一个定义的值。如果racer B 排名靠前的结果优于 A ,则返回1.如果racer 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) && 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;
});

答案 1 :(得分:1)

这是另一种算法,但我认为Max Zuber的解决方案更有效。无论如何:

通过 array_count_values

定义每个参赛者的位数
foreach ($racers as &$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]) && !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;
        }
    }
});