PHP:优化数组迭代
我正在研究一种基于最高分数对团队进行排序的算法。团队将根据球员名单生成。创建团队的条件是PHP:优化数组迭代,php,optimization,multidimensional-array,nested-loops,Php,Optimization,Multidimensional Array,Nested Loops,我正在研究一种基于最高分数对团队进行排序的算法。团队将根据球员名单生成。创建团队的条件是 它应该有6名球员 6名球员的集体工资必须低于或等于50K 团队将根据最高集体预测生成 我所做的是生成团队的所有可能性,然后对它们进行检查,排除那些薪水超过5万英镑的团队,然后根据预测对其余的团队进行排序。但是产生所有的可能性需要很多时间,有时它会消耗所有的内存。对于160名玩家的名单,大约需要90秒。这是密码 $base_array = array(); $query1 = mysqli_query($
- 它应该有6名球员
- 6名球员的集体工资必须低于或等于50K
- 团队将根据最高集体预测生成
$base_array = array();
$query1 = mysqli_query($conn, "SELECT * FROM temp_players ORDER BY projection DESC");
while($row1 = mysqli_fetch_array($query1))
{
$player = array();
$mma_id = $row1['mma_player_id'];
$salary = $row1['salary'];
$projection = $row1['projection'];
$wclass = $row1['wclass'];
array_push($player, $mma_id);
array_push($player, $salary);
array_push($player, $projection);
array_push($player, $wclass);
array_push($base_array, $player);
}
$result_base_array = array();
$totalsalary = 0;
for($i=0; $i<count($base_array)-5; $i++)
{
for($j=$i+1; $j<count($base_array)-4; $j++)
{
for($k=$j+1; $k<count($base_array)-3; $k++)
{
for($l=$k+1; $l<count($base_array)-2; $l++)
{
for($m=$l+1; $m<count($base_array)-1; $m++)
{
for($n=$m+1; $n<count($base_array)-0; $n++)
{
$totalsalary = $base_array[$i][1]+$base_array[$j][1]+$base_array[$k][1]+$base_array[$l][1]+$base_array[$m][1]+$base_array[$n][1];
$totalprojection = $base_array[$i][2]+$base_array[$j][2]+$base_array[$k][2]+$base_array[$l][2]+$base_array[$m][2]+$base_array[$n][2];
if($totalsalary <= 50000)
{
array_push($result_base_array,
array($base_array[$i], $base_array[$j], $base_array[$k], $base_array[$l], $base_array[$m], $base_array[$n],
$totalprojection, $totalsalary)
);
}
}
}
}
}
}
}
usort($result_base_array, "cmp");
$base_array=array();
$query1=mysqli_query($conn,“按投影说明从临时玩家订单中选择*);
while($row1=mysqli\u fetch\u数组($query1))
{
$player=array();
$mma_id=$row1['mma_player_id'];
$salary=$row1['salary'];
$projection=$row1['projection'];
$wclass=$row1['wclass'];
阵列推送($player,$mma_id);
阵列推送($player,$salary);
阵列推送($player,$projection);
阵列推送($player,$wclass);
阵法推送($base\u阵法,$player);
}
$result_base_array=array();
$totalsalary=0;
对于($i=0;$i,因为数组中的元素数量可能非常大(例如100名玩家可以生成1.2*10^9个团队),您无法将其保存在内存中。请尝试将生成的数组按部分保存到文件中(每次保存后截断数组)。然后使用外部文件排序
它会很慢,但至少不会因为记忆而倒下
如果你需要排名前n的团队(比如10个预测最高的团队)然后,您应该将生成结果基数组的代码转换为生成器,这样它将yeld
下一个团队,而不是将其推到数组中。然后迭代此生成器。在每次迭代中,向排序后的结果数组添加新项并剪切冗余元素。这取决于工资是否经常是排除的原因你也可以在其他循环中对此进行测试。如果在选择了4名玩家之后,他们的总工资已经超过50K,那么选择剩下的2名玩家是没有用的。这可以为你节省一些迭代
这可以通过记住组中最低的6份工资来进一步改进,然后检查在选择4名成员后,如果你要添加2份最低的现有工资,你是否仍会保持在50K以下。如果这不可能,那么再次尝试添加剩余的两名玩家是没有用的。当然,这可以在s的每个阶段完成选举(选择1名球员、2名球员后,…)
另一个相关的改进是,当你按升薪对数据进行排序时。如果在选择了第四名球员后,上述逻辑使你得出结论,你不能通过再增加两名球员而保持在50K以下,那么用数据系列中的下一名球员替换第四名球员也没有用:该球员的薪水会更高,因此它也将屈服于超过50K的总数。这意味着您可以立即回溯并处理第三个玩家选择
正如其他人所指出的,潜在解决方案的数量是巨大的。对于160个团队和6名成员的团队规模,组合的数量是:
160 . 159 . 158 . 157 . 156 . 155
--------------------------------- = 21 193 254 160
6 . 5 . 4 . 3 . 2
210亿条参赛作品对你的记忆来说太长了,可能对你也没什么用处:你真的会对第4432456911位的球队感兴趣吗
你可能会对这些团队中的前十名感兴趣(就预测而言)。这可以通过保留10个最佳团队的列表来实现,然后,当你得到一个薪水可以接受的新团队时,你将其添加到该列表中,并保持其排序(通过二进制搜索),并从前10名中弹出投影最低的条目
以下是您可以使用的代码:
$base_array = array();
// Order by salary, ascending, and only select what you need
$query1 = mysqli_query($conn, "
SELECT mma_player_id, salary, projection, wclass
FROM temp_players
ORDER BY salary ASC");
// Specify with option argument that you only need the associative keys:
while($row1 = mysqli_fetch_array($query1, MYSQLI_ASSOC)) {
// Keep the named keys, it makes interpreting the data easier:
$base_array[] = $row1;
}
function combinations($base_array, $salary_limit, $team_size) {
// Get lowest salaries, so we know the least value that still needs to
// be added when composing a team. This will allow an early exit when
// the cumulative salary is already too great to stay under the limit.
$remaining_salary = [];
foreach ($base_array as $i => $row) {
if ($i == $team_size) break;
array_unshift($remaining_salary, $salary_limit);
$salary_limit -= $row['salary'];
}
$result = [];
$stack = [0];
$sum_salary = [0];
$sum_projection = [0];
$index = 0;
while (true) {
$player = $base_array[$stack[$index]];
if ($sum_salary[$index] + $player['salary'] <= $remaining_salary[$index]) {
$result[$index] = $player;
if ($index == $team_size - 1) {
// Use yield so we don't need to build an enormous result array:
yield [
"total_salary" => $sum_salary[$index] + $player['salary'],
"total_projection" => $sum_projection[$index] + $player['projection'],
"members" => $result
];
} else {
$index++;
$sum_salary[$index] = $sum_salary[$index-1] + $player['salary'];
$sum_projection[$index] = $sum_projection[$index-1] + $player['projection'];
$stack[$index] = $stack[$index-1];
}
} else {
$index--;
}
while (true) {
if ($index < 0) {
return; // all done
}
$stack[$index]++;
if ($stack[$index] <= count($base_array) - $team_size + $index) break;
$index--;
}
}
}
// Helper function to quickly find where to insert a value in an ordered list
function binary_search($needle, $haystack) {
$high = count($haystack)-1;
$low = 0;
while ($high >= $low) {
$mid = (int)floor(($high + $low) / 2);
$val = $haystack[$mid];
if ($needle < $val) {
$high = $mid - 1;
} elseif ($needle > $val) {
$low = $mid + 1;
} else {
return $mid;
}
}
return $low;
}
$top_team_count = 10; // set this to the desired size of the output
$top_teams = []; // this will be the output
$top_projections = [];
foreach(combinations($base_array, 50000, 6) as $team) {
$j = binary_search($team['total_projection'], $top_projections);
array_splice($top_teams, $j, 0, [$team]);
array_splice($top_projections, $j, 0, [$team['total_projection']]);
if (count($top_teams) > $top_team_count) {
// forget about lowest projection, to keep memory usage low
array_shift($top_teams);
array_shift($top_projections);
}
}
$top_teams = array_reverse($top_teams); // Put highest projection first
print_r($top_teams);
$base_array=array();
//按薪资、升序排序,仅选择您需要的内容
$query1=mysqli\u查询($conn,“
选择mma_球员id、工资、投影、wclass
来自临时工队的球员
按薪金(ASC)订购;
//使用选项参数指定仅需要关联键:
而($row1=mysqli_fetch_数组($query1,mysqli_ASSOC)){
//保留命名键,这样可以更轻松地解释数据:
$base_数组[]=$row1;
}
功能组合($base\u array、$salary\u limit、$team\u size){
//拿到最低的薪水,这样我们就知道了仍然需要的最低价值
//在组建团队时添加。这将允许在
//累计工资已经太高了,不能低于限额。
$剩余工资=[];
foreach($i=>$row的基本数组){
如果($i==$team_size)中断;
数组\取消移位($剩余\工资,$工资\限额);
$salary_limit-=$row['salary'];
}
$result=[];
$stack=[0];
$sum_工资=[0];
$sum_projection=[0];
$index=0;
while(true){
$player=$base_数组[$stack[$index]];
如果($sum_salary[$index]+$player['salary']为什么要在PHP
中执行此操作。您可以使用条件进行查询以获取结果。简单地说,嵌入循环从来都不是一件好事,您想做的是优化获取数据的方式,并且您不应该这样做疯狂的嵌入循环。您的代码有点疯狂。发布您的表模式以查看问题是否可以解决这是一个非常有趣的问题。你能给数据集(如果它不包含个人信息吗?)一些关联:选择wclass,SUM(sallary)作为total_sallary,SUM(projection)作为total_projection从temp_players组按wclass have total_sallary
$base_array = array();
// Order by salary, ascending, and only select what you need
$query1 = mysqli_query($conn, "
SELECT mma_player_id, salary, projection, wclass
FROM temp_players
ORDER BY salary ASC");
// Specify with option argument that you only need the associative keys:
while($row1 = mysqli_fetch_array($query1, MYSQLI_ASSOC)) {
// Keep the named keys, it makes interpreting the data easier:
$base_array[] = $row1;
}
function combinations($base_array, $salary_limit, $team_size) {
// Get lowest salaries, so we know the least value that still needs to
// be added when composing a team. This will allow an early exit when
// the cumulative salary is already too great to stay under the limit.
$remaining_salary = [];
foreach ($base_array as $i => $row) {
if ($i == $team_size) break;
array_unshift($remaining_salary, $salary_limit);
$salary_limit -= $row['salary'];
}
$result = [];
$stack = [0];
$sum_salary = [0];
$sum_projection = [0];
$index = 0;
while (true) {
$player = $base_array[$stack[$index]];
if ($sum_salary[$index] + $player['salary'] <= $remaining_salary[$index]) {
$result[$index] = $player;
if ($index == $team_size - 1) {
// Use yield so we don't need to build an enormous result array:
yield [
"total_salary" => $sum_salary[$index] + $player['salary'],
"total_projection" => $sum_projection[$index] + $player['projection'],
"members" => $result
];
} else {
$index++;
$sum_salary[$index] = $sum_salary[$index-1] + $player['salary'];
$sum_projection[$index] = $sum_projection[$index-1] + $player['projection'];
$stack[$index] = $stack[$index-1];
}
} else {
$index--;
}
while (true) {
if ($index < 0) {
return; // all done
}
$stack[$index]++;
if ($stack[$index] <= count($base_array) - $team_size + $index) break;
$index--;
}
}
}
// Helper function to quickly find where to insert a value in an ordered list
function binary_search($needle, $haystack) {
$high = count($haystack)-1;
$low = 0;
while ($high >= $low) {
$mid = (int)floor(($high + $low) / 2);
$val = $haystack[$mid];
if ($needle < $val) {
$high = $mid - 1;
} elseif ($needle > $val) {
$low = $mid + 1;
} else {
return $mid;
}
}
return $low;
}
$top_team_count = 10; // set this to the desired size of the output
$top_teams = []; // this will be the output
$top_projections = [];
foreach(combinations($base_array, 50000, 6) as $team) {
$j = binary_search($team['total_projection'], $top_projections);
array_splice($top_teams, $j, 0, [$team]);
array_splice($top_projections, $j, 0, [$team['total_projection']]);
if (count($top_teams) > $top_team_count) {
// forget about lowest projection, to keep memory usage low
array_shift($top_teams);
array_shift($top_projections);
}
}
$top_teams = array_reverse($top_teams); // Put highest projection first
print_r($top_teams);