提问人:Mira 提问时间:11/14/2023 最后编辑:mickmackusaMira 更新时间:11/15/2023 访问量:110
在指定约束范围内使用随机数量填充数据集
Populate dataset with random amounts within nominated constraints
问:
我正在尝试从大量球员中创建一个由 11 名球员组成的梦幻板球队。
对于球队,我对每种类型的球员都有基本的最低和最高要求。我分配了这样的值:
$min_wicket_keeper = 1;
$min_batsman = 3;
$min_all_rounders = 1;
$min_bowlers = 2;
$max_wicket_keeper = 3;
$max_batsman = 5;
$max_all_rounders = 5;
$max_bowlers = 4;
我有这样的球员总数:
$total_wicket_keepers = 2;
$total_batsman = 6;
$total_all_rounders = 5;
$total_bowlers = 5;
你可以看到我总共有 18 名球员。现在我想创建一个由 11 名玩家组成的团队,分配随机类型的玩家——记住玩家的最低和最高要求。
示例 1
$wicket_keeper_limit = 1;
$batsman_limit = 4;
$all_rounder_limit = 4;
$bowler_limit = 2;
//so total 11
示例 2
$wicket_keeper_limit = 2;
$batsman_limit = 3;
$all_rounder_limit = 3;
$bowler_limit = 3;
//so total 11
我想要为每种类型分配一个随机数,但总数应为 11,不应低于最低要求,也不应大于每种类型的可用玩家总数,然后是最大限制。
我尝试过这样的代码
$min_wicket_keeper = 1;
$min_batsman = 3;
$min_all_rounders = 1;
$min_bowlers = 2;
$max_wicket_keeper = 3;
$max_batsman = 5;
$max_all_rounders = 5;
$max_bowlers = 4;
$total_wicket_keepers = 2;
$total_batsman = 6;
$total_all_rounders = 5;
$total_bowlers = 5;
$total_players_match = $total_wicket_keepers+$total_batsman+$total_all_rounders+$total_bowlers;
echo $total_players_match;
if ($total_players_match > 11) {
$remain_players = 11;
if ($total_wicket_keepers > $min_wicket_keeper) {
$wicket_keeper_limit = rand($min_wicket_keeper,$total_wicket_keepers);
$remain_players = $remain_players-$wicket_keeper_limit;
} else {
$wicket_keeper_limit = $total_wicket_keepers;
$remain_players = $remain_players-$wicket_keeper_limit;
}
echo "WK: ".$wicket_keeper_limit." REMAIN: ".$remain_players."<br>";
if ($total_batsman>$min_batsman) {
$batsman_limit = rand($min_batsman,$total_batsman);
$remain_players = $remain_players-$batsman_limit;
if ($remain_players > ($total_bowlers + $total_all_rounders)) {
$batsman_limit = ($min_batsman + $remain_players) - ($total_bowlers+$total_all_rounders);
$remain_players = $remain_players-$batsman_limit;
}
} else {
$batsman_limit = $total_batsman;
$remain_players = $remain_players-$batsman_limit;
}
echo "BT: " . $batsman_limit . " REMAIN: " . $remain_players . "<br>";
if ($total_bowlers > $min_bowlers) {
$bowler_limit = rand($min_bowlers, $total_bowlers);
$remain_players = $remain_players - $bowler_limit;
if ($remain_players > $total_all_rounders) {
$bowler_limit = $total_bowlers;
$remain_players = $remain_players - $bowler_limit;
}
} else {
$bowler_limit = $total_bowlers;
$remain_players = $remain_players - $bowler_limit;
}
echo "BOL:" . $bowler_limit . " REMAIN:" . $remain_players . "<br>";
$all_rounder_limit = $remain_players;
echo "ALL: " . $all_rounder_limit . " REMAIN: " . $remain_players . "<br>";
} else {
$wicket_keeper_limit = $total_wicket_keepers;
$batsman_limit = $total_batsman;
$all_rounder_limit = $total_all_rounders;
$bowler_limit = $total_bowlers;
}
echo "WK:" . $wicket_keeper_limit . "<br>";
echo "BT:" . $batsman_limit . "<br>";
echo "BO:" . $bowler_limit . "<br>";
echo "AL:" . $all_rounder_limit . "<br>";
但它没有遵循我的最低和最高要求。有时我得到的投球手是 0,有时我得到的全圆高达 6。
这是在线小提琴链接
编辑:根据评论,我应该明确一点,我将生成多个团队,并在 while 循环中使用上述代码,就像 50 支球队一样,每种类型都有不同/随机的球员,比如有些球队有 5 名击球手,有些球队只有 3 名击球手。
当我完成上述代码工作时,我稍后会根据限制从我的数据库中获取玩家,我为每种类型获取了玩家。
答:
0赞
Wimanicesir
11/15/2023
#1
对不起,你的代码对我来说太难处理了。根据您的条件,我编写了以下代码:
<?php
// Remapped your variables because it was too much
$constraints = [
'wicket_keeper' => ['min' => 1, 'max' => 3],
'batsman' => ['min' => 3, 'max' => 5],
'all_rounders' => ['min' => 1, 'max' => 5],
'bowlers' => ['min' => 2, 'max' => 4],
];
// These are the current values to assign
$values = [
'wicket_keeper' => 2,
'batsman' => 6,
'all_rounders' => 5,
'bowlers' => 5,
];
// The first problem is that the maximums should be adjusted to the values we have
foreach ($values as $key => $value) {
if ($value < $constraints[$key]['max']){
$constraints[$key]['max'] = $value;
}
}
// Vice versa we need to do this for the minimums
// I now did this manually, but I think you get the point
$result = [
'wicket_keeper' => 1,
'batsman' => 3,
'all_rounders' => 1,
'bowlers' => 2,
];
// We keep track of possible options
$options = array_keys($result);
// Init
$totalPlayers = 0;
$max = 0;
// This is minus 7 because of your minimum requirements, also done manually
// But of course you can calculate this as well.
$teamLimit = 11 - 7;
while($totalPlayers < $teamLimit) {
// Pick a random type
$random = rand(0, count($options) - 1);
// Get key
$key = $options[$random];
// Add one player to the random type
$result[$key] += 1;
$totalPlayers++;
// Check if max is reached
// If so, remove it from possible options
if ($result[$key] >= $constraints[$key]['max']){
unset($options[$key]);
}
}
var_dump($result);
我希望评论足够清楚。
评论
0赞
mickmackusa
11/15/2023
我不明白反之亦然部分的意图。如果播放器类型的可用性小于最小值,则应引发异常以关闭整个脚本。此外,将手动流程添加到动态需求会使此脚本成为不可用的答案。
0赞
Wimanicesir
11/15/2023
反之亦然,首先要设定最低要求。你是对的,它可能会失败,应该有错误处理。关于手动过程,这当然必须被替换,但我认为这很清楚,而不是这个问题的问题。
0赞
mickmackusa
11/15/2023
#2
您可以将此脚本构建为单个函数/方法,或者更好的做法是实践单一责任原则,并具有多个函数/方法,这些函数/方法只执行一项任务。为了避免过多地扩展代码段,我将仅将我的建议显示为多责任函数。
- 传入团队创建设置。
- 实现逻辑防护条件,以便在设置阻止填充整个团队时提醒你。
- 对玩家总数应用最大限制。
- 作为捷径,为您的团队提供所有指定的最小值。
- 在循环中一次随机选择一个仓位,并在池中“消耗”该仓位,这样仓位就不会从池中超额抽取。
- 当团队已满或池为空时,终止循环。
- 返回已填充的团队,或在团队无法完全填充时提醒用户。
代码:(演示)
function randomizeTeam(
int $teamSize,
array $positionPool,
array $positionMins = [],
array $positionMaxs = []
): array {
// guard conditions
foreach ($positionMins as $pos => $min) {
if (!key_exists($pos, $positionPool) || $positionPool[$pos] < $min) {
throw new Exception('Position pool cannot accommodate minimum required positions');
}
}
// input preparation
foreach ($positionMaxs as $pos => $max) {
if (key_exists($pos, $positionPool) && $positionPool[$pos] > $max) {
$positionPool[$pos] = $max;
}
}
// seed team
$team = [];
$sum = 0;
foreach ($positionPool as $pos => &$pool) {
$team[$pos] = $positionMins[$pos] ?? 0;
$pool -= $team[$pos];
if (!$pool) {
unset($positionPool[$pos]); // remove exhausted pool
}
$sum += $team[$pos];
}
// add random positions
while ($sum < $teamSize && $positionPool) {
$pos = array_rand($positionPool);
++$team[$pos];
--$positionPool[$pos];
if (!$positionPool[$pos]) {
unset($positionPool[$pos]); // remove exhausted pool
}
++$sum;
}
// another guard condition
if (array_sum($team) < $teamSize) {
throw new Exception('Position pool was exhausted before filling team');
}
return $team;
}
var_export(
randomizeTeam(
11,
[
'wicket_keeper' => 2,
'batsman' => 6,
'all_rounders' => 5,
'bowlers' => 5,
],
[
'wicket_keeper' => 1,
'batsman' => 3,
'all_rounders' => 1,
'bowlers' => 2,
],
[
'wicket_keeper' => 3,
'batsman' => 5,
'all_rounders' => 5,
'bowlers' => 4,
]
)
);
潜在输出:
array (
'wicket_keeper' => 2,
'batsman' => 4,
'all_rounders' => 2,
'bowlers' => 3,
)
一些附加说明:
- 最好以数组形式声明输入数据,这样您就可以享受循环和数组函数的动态优势,同时避免变量。
- 上述脚本旨在允许可扩展的仓位池,并允许最小和/或最大仓位约束,这些约束不需要提及主池中的所有仓位。
评论