在指定约束范围内使用随机数量填充数据集

Populate dataset with random amounts within nominated constraints

提问人:Mira 提问时间:11/14/2023 最后编辑:mickmackusaMira 更新时间:11/15/2023 访问量:110

问:

我正在尝试从大量球员中创建一个由 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 名击球手。

当我完成上述代码工作时,我稍后会根据限制从我的数据库中获取玩家,我为每种类型获取了玩家。

PHP 数组 循环随机 约束

评论

0赞 Wimanicesir 11/14/2023
我希望分配一堆 while 循环,直到满足您的条件。此外,您只需处理数字即可。难道你不应该有一系列球员可供选择吗?我不明白你想达到什么目的。
0赞 Mira 11/14/2023
@Wimanicesir当我使用代码获取每种类型播放器的 SET 时,我将调用 mysql 数据库来获取该数量的播放器。我希望在这个阶段固定玩家数量,稍后,我将根据每种类型的分配玩家从数据库中获取玩家。
0赞 Wimanicesir 11/14/2023
好的,但是您的要求不是很清楚。我想你想先用最少的团队填充团队,然后每个组添加一个,直到你有一个完整的团队。如果一支球队只由球员组成,为什么还要有两个守门员?多个团队之间有什么区别?
0赞 Mira 11/14/2023
@Wimanicesir我想要多支球队拥有随机球员,这就是为什么我想像上面我说过的那样,有些球队会有 4 名击球手,有些球队会有 5 名击球手,等等对于其他类型的球员。
0赞 Wimanicesir 11/14/2023
但要清楚。有些球队会有两个守门员?

答:

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,
)

一些附加说明:

  • 最好以数组形式声明输入数据,这样您就可以享受循环和数组函数的动态优势,同时避免变量。
  • 上述脚本旨在允许可扩展的仓位池,并允许最小和/或最大仓位约束,这些约束不需要提及主池中的所有仓位。