Как я могу собрать элементы в массиве? Скажем, у меня есть массив бойцов . И я хочу связать их по их весам . Бойцы с самыми близкими весами должны быть спарены как лучший матч . Но если они находятся в одной команде, их не следует спаривать .
Вывод:
Я изучал эту тему и нашел нечто подобное, но не совсем: случайные, но уникальные пары, с условиями
Было бы очень полезно помочь. Заранее спасибо!
Мне очень понравился ваш вопрос, поэтому я сделал полную надежную версию.
<?php header("Content-type: text/plain"); error_reporting(E_ALL); /** * @class Fighter * @property $name string * @property $weight int * @property $team string * @property $paired Fighter Will hold the pointer to the matched Fighter */ class Fighter { public $name; public $weight; public $team; public $paired = null; public function __construct($name, $weight, $team) { $this->name = $name; $this->weight = $weight; $this->team = $team; } } /** * @function sortFighters() * * @param $a Fighter * @param $b Fighter * * @return int */ function sortFighters(Fighter $a, Fighter $b) { return $a->weight - $b->weight; } $fighterList = array( new Fighter("A", 60, "A"), new Fighter("B", 65, "A"), new Fighter("C", 62, "B"), new Fighter("D", 60, "B"), new Fighter("E", 64, "C"), new Fighter("F", 66, "C") ); usort($fighterList, "sortFighters"); foreach ($fighterList as $fighterOne) { if ($fighterOne->paired != null) { continue; } echo "Fighter $fighterOne->name vs "; foreach ($fighterList as $fighterTwo) { if ($fighterOne->team != $fighterTwo->team && $fighterTwo->paired == null) { echo $fighterTwo->name . PHP_EOL; $fighterOne->paired = $fighterTwo; $fighterTwo->paired = $fighterOne; break; } } }
usort()
массив по весу (используя usort()
и функцию сортировки sortFighters()
для сортировки по весовому свойству каждого элемента. $fighterVariable->paired
) Это просто расширение ответа Истины на основе комментариев:
Первое, что я сделал бы по-другому, – это основное отслеживание игроков.
$unassignedPlayers = $fighterList;
Чем алгоритм будет работать так: подготовьте список команд (если вы используете базу данных, используйте SELECT DISTINCT
или GROUP BY teams.id
):
$teams = array(); foreach( $fighterList as $fighter){ $teams[] = $figter->team; } $teams = array_unique( $teams);
Затем нам понадобится метод, который будет разделять массив бойцов (скажем, у нас есть команды {A,A,B,B,C,C}
мы хотим разбить на {A,A}
, {B,B,C,C}
):
// Don't use string type declaration, it's just ilustrating function splitFighters( array $input, string $team){ $inteam = array(); $outteam = array(); foreach( $input as $fighter){ if( $figter->team == $team){ $inteam[] = $fighter; } else { $outteam[] = $fighter; } } return array( $inteam, $outteam); }
Теперь, когда у нас есть это, мы можем создать функцию, которая будет сортировать членов команды:
function assignFighters( array &$input, array $teams, array &$output){ // Nothing to work with? if( !count( $input)){ return true; } // No team left and still unassigned players, that fatal error if( !cont( $teams)){ throw new Exception( 'Unassigned players occurred!'); } // Shift team $team = array_shift( $teams); // Split into in and out team list( $inteam, $outteam) = splitFighters( $input, $team); // Inteam is already empty (let's say all players were assigned before) // Just go deeper (where's DiCaprio?) if( !count( $inteam) && count( $teams)) { return assignFighters( $input, $teams, $output) } // There're unassigned and nonassignable players in this team // This is error and we'll have to deal with it later if( !count($outteam)){ $input = $inteam; // Propagate unassigned players to main return false; } // Sort both teams by fighters weight // Uses Truth's comparison function usort($inteam, "sortFighters"); usort($outteam, "sortFighters"); // Fig = Fighter while( $fig1 = array_shift( $inteam)){ // Are there any players to work with if( !count( $outteam)){ array_unshift( $inteam, $fig1); $input = $inteam; // Propagate unassigned players to main return false; } // Assign players to each other $fig2 = array_shift( $outteam); $fig1->paired = $fig2; $fig2->paired = $fig1; // This will propagate players to main nicely $output[] = $fig1; $output[] = $fig2; } // Still here? Great! $inteam is empty now // $outteam contains all remaining players $input = $outteam; return assignFighters( $input, $teams,$output); }
До этого момента вы могли бы использовать алгоритм Истины, но это должно иметь лучшее соответствие веса и представляет собой то, что вы намереваетесь более четко, но в любом случае теперь вы получаете $unassignedPlayers
в работу:
$assignedPlayers = array(); $state = assignFighters( $unassignedPlayers, $teams, $assignedPlayers); // Note: $state === !(bool)count($unassignedPlayers) // should evaluate as true, otherwise I'm having an error in algorithm
Итак, что теперь … Если у вас $state === false
resp. count( $unassignedPlayers) > 0
что-то пошло не так, и нам нужно применить магию. Как эта магия будет работать:
// Keep the trace of swapped players so we don't end up in endless loop $swappedPlayers = array(); // Browse all unassigned players while( $fig1 = array_shift( $unassignedPlayers)){ // Store as swapped $swappedPlayers[] = $fig1; // At first check whether there's not unassigned player in the different team // this shouldn't occur in first iteration (all fighters should be from one team // in the beginning) but this is most effective part of this method foreach( $unassignedPlayers as $key => $fig2){ if( $fig2->team != $fig1->team){ $fig1->pair = $fig2; $fig2->pair = $fig1; continue; } } // No luck, normal magic required list( $inteam, $outteam) = splitFighters( $assignedPlayers, $fig1->team); $fig2 = null; // I like my variables initialized, this actually quite important // Now select someone from $outteam you will want to swap fights with. // You may either iterate trough all players until you find best weight // match or select it random, or whatever, I'll go with random, // it's your job to implement better selection $i = 1000; // Limit iterations while(($i--) > 1){ $key1 = array_rand( $outteam, 1); if( $outteam[$key]->team == $fig1->team){ continue; // No point in swapping fit team member } // No recursive swaps if( in_array( $outteam[$key], $swappedPlayers)){ continue; } // This may speed things really up: // That means we'll get rid of 2 players due to foreach loop at the beggining // However I'm not sure how this condition will really work if( $outteam[$key]->pair->team == $fig1->team){ continue; } // Store matched fighter $fig2 = $outteam[$key]; // Unset pair from another fighter $fig2->pair->pair = null; // Find the pair in $assignedPlayers and move it to $unassignedPlayers $key = array_search( $fig2->pair, $assignedPlayers); if( $key === false){ throw new Exception( 'Cannot find pair player'); } unset( $assignedPlayers[$key]); $unassignedPlayers[] = $fig2->pair; $swappedPlayers[] = $fig2->pair; // Remove pair from self $fig2->pair = null; $swappedPlayers[] = $fig2; break; // hh, try forgetting this one :) } // This shouldn't be happening if( $fig2 === null){ throw new Exception( 'Didn\'t find good match in 1000 iterations.'); } // Ok now just make matches as go to the next iteration $fig1->pair = $fig2; $fig2->pair = $fig1; // And store those $assignedPlayers[] = $fig1; $assignedPlayers[] = $fig2; }
Я написал все это из головы (это был вызов), протестировать его и оставить заметки в комментариях, пожалуйста 🙂
Сортируйте массив по весу. Затем у вас будут пары весов, которые близки друг к другу.