2013-10-15 68 views
3

我有一个代码可以为比赛生成支架表。我有球员,每个球员都与一所学校相关。我需要与球员进行阵列排序,以便同一所学校的球员没有第一场比赛(或者较低的同校比赛)。PHP按两组排序数组避免合并具有相同值的项目

像这样:

$players = array( 
      array('name' => 'juan', 'school' => 'ABC'), // 0 
      array('name' => 'leo', 'school' => 'ABC'), // 1 
      array('name' => 'arnold', 'school' => 'DEF'), // 2 
      array('name' => 'simon', 'school' => 'DEF'), // 3 
      array('name' => 'luke', 'school' => 'ECD'), // 4 
      array('name' => 'ash', 'school' => 'ECD'), // 5 
      ); 
// code to sort here 

array_chunk($players, 2); // this generate an array with groups of two for matches. 

在上面的例子[0]和[1]不能去在一起,因为它们是在相同的学校。例如,[0]可以与3一起使用。

我想与usort,但我不知道什么是正确的方法来解决这个问题。

回答

1

好的,一个新的答案重新审查了这个问题。算法,我认为,应该如此:

  • 迭代未分配的球员(注意,此列表一次减少2)。
  • 找到学校中剩余的玩家数量最多的玩家不在学校玩家当前的迭代数
  • 如果上述检查没有找到任何学校的学校,请使用与当前学校相同的学校如果没有其他玩家留在分配池中,则这个效果是同一所学校的玩家可以互相玩耍。
  • 分配从我们刚发现
  • 对当前迭代的球员,任意玩家
  • 从池中取出双方球员在学校任意玩家

实现明智的,我发现它更容易维护2个指标 - 学校和球员之一。我将它捆绑到几个类中,因为对象的固有参照性使生活更轻松。我的代码是低于...它可以在框中使用,但可能需要一些调整。

<?php 

class School { 
     protected $name; 
     protected $players = []; 

     public function __construct($name) { 
       $this->name = $name; 
     } 

     public function get_name() { 
       return $this->name; 
     } 

     public function add_player($name) { 
       $this->players[] = $name; 
     } 

     public function del_player($name) { 
       if (($index = array_search($name, $this->players)) !== false) { 
         unset($this->players[$index]); 
       } 
     } 

     public function player_count() { 
       return count($this->players); 
     } 

     public function get_player() { 
       if (!reset($this->players)) { 
         return false; 
       } 

       return [ 
         'school' => $this->name, 
         'name' => reset($this->players), 
       ]; 
     } 
} 

class Players { 
     protected $schools_index = []; 
     protected $player_index = []; 

     public function add_player($school, $player) { 
       // Create school if not exists 
       if (!isset($this->schools_index[$school])) { 
         $this->schools_index[$school] = new School($school); 
       } 

       // Add player to school and own index 
       $this->schools_index[$school]->add_player($player); 
       $this->player_index[$player] = $school; 
     } 

     public function del_player($school, $player) { 
       // From school index 
       $this->schools_index[$school]->del_player($player); 

       // From own index 
       if (isset($this->player_index[$player])) { 
         unset($this->player_index[$player]); 
       } 
     } 

     public function biggest_school($exclude = null) { 
       $rtn = null; 

       // Find school excluding the exclude. Don't get schools with nobody left in them. 
       foreach ($this->schools_index as $name=>$school) { 
         if ((!$exclude || $name != $exclude) && ($school->player_count()) && (!$rtn || $rtn->player_count() < $school->player_count())) { 
           $rtn = $school; 
         } 
       } 

       // If we didn't get a school, shitcan the exclude and try the excluded school 
       if (!$rtn && $exclude) { 
         if ($this->schools_index[$exclude]->player_count()) { 
           $rtn = $this->schools_index[$exclude]; 
         } 
       } 

       return $rtn; 
     } 

     public function get_player() { 
       if (!reset($this->player_index)) { 
         return false; 
       } 

       return [ 
         'school' => reset($this->player_index), 
         'name' => key($this->player_index), 
       ]; 
     } 

     public static function from_players_arr(array $players) { 
       $obj = new static(); 

       foreach ($players as $player) { 
         // Add to indexes 
         $obj->add_player($player['school'], $player['name']); 
       } 

       return $obj; 
     } 
} 

$players = array(
     array('name' => 'juan', 'school' => 'ABC'), 
     array('name' => 'leo', 'school' => 'ABC'), 
     array('name' => 'arnold', 'school' => 'ABC'), 
     array('name' => 'simon', 'school' => 'ABC'), 
     array('name' => 'luke', 'school' => 'ABC'), 
     array('name' => 'alan', 'school' => 'JKL'), 
     array('name' => 'jeff', 'school' => 'BAR'), 
     array('name' => 'paul', 'school' => 'FOO'), 
); 

$players_obj = Players::from_players_arr($players); 

$pairs = []; 

while ($player = $players_obj->get_player()) { 
     $players_obj->del_player($player['school'], $player['name']); 

     $opponent = $players_obj->biggest_school($player['school'])->get_player(); 

     $pairs[] = [ 
       $player['name'], 
       $opponent['name'], 
     ]; 

     $players_obj->del_player($opponent['school'], $opponent['name']); 
} 

var_dump($pairs); 

输出如下:

array(4) { 
    [0] => 
    array(2) { 
    [0] => 
    string(4) "juan" 
    [1] => 
    string(4) "alan" 
    } 
    [1] => 
    array(2) { 
    [0] => 
    string(3) "leo" 
    [1] => 
    string(4) "jeff" 
    } 
    [2] => 
    array(2) { 
    [0] => 
    string(6) "arnold" 
    [1] => 
    string(4) "paul" 
    } 
    [3] => 
    array(2) { 
    [0] => 
    string(5) "simon" 
    [1] => 
    string(4) "luke" 
    } 
} 
0

我们要做的,是在2组拆分球员:竞争者1个&竞争者2.我们要填补连续球员争夺一个同校的:

如果我们命名学校简洁一个字母,我们就基本上拥有的是:

A A A A B B B C 
C C D D E E F F 

或者,如果我们甩掉它,它变得更清晰:

A C 
A C 
A D 
A D 
B E 
B E 
B F 
C F 

如果一个学校有>的玩家总人数的一半,会发生什么?好吧,让我们来看看:

A A A A A 
A B B C D 

所以:

A A <= one A vs. A, which is unavoidable, but the method still works. 
A B 
A B 
A C 
A D 

我在这里被骗了一下:我整理出从最大的学校选手第一。但是,只要我们将学校分组在一起,它仍然有效。让我们把我的$a = range('A','F'); shuffle($a):输出,在这里产生了:FCADBE,这给了我们:

F A 
F D 
C D 
C B 
C B 
A B 
A E 
A E 

..这工作,也为A>半:

C A 
A A <= that one double again, unavoidable 
A D 
A B 
A B 

让我们打入部分这一点。我们要做的是:

  1. 玩家通过学校
  2. 突破此有序阵列分为2组排序。
  3. 通过从第一组&中添加一个从第二组开始按顺序创建配对。

砍倒它是如此,你可以找到答案的优点:

  1. hundreds of questions on SO
  2. this is a nice answer
  3. 我们可以使用一个MultiIterator,这将是一个合乎逻辑的(和工作)的选择,但我会告诉你另一种创建2个阵列对的简短方法(或者如果您有3个阵列等,则为三元组)

所以,让我们做到这一点:

//sort by school 
$players = ... your array ... 
usort($players,function($playerA, $playerB){ 
    return strcmp($playerA['school'], $playerB['school']); 
}); 
//voila, sorted 

//break this into 2 groups: 
$size = ceil(count($players)/2); // round UP 
$groupA = array_slice($players,0,$size); 
$groupB = array_slice($players,$size); 

//create our duels array: 
$duels = array_map(null, $groupA, $groupB); 

$duels现在有这项内容与您输入:

[ 
    [ 
     { 
      "name": "juan", 
      "school": "ABC" 
     }, 
     { 
      "name": "arnold", 
      "school": "DEF" 
     } 
    ], 
    [ 
     { 
      "name": "leo", 
      "school": "ABC" 
     }, 
     { 
      "name": "ash", 
      "school": "ECD" 
     } 
    ], 
    [ 
     { 
      "name": "simon", 
      "school": "DEF" 
     }, 
     { 
      "name": "luke", 
      "school": "ECD" 
     } 
    ] 
] 
相关问题