2013-10-15 97 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" 
     } 
    ] 
] 
相關問題