链接在一起的两个范围之间的随机数输出

链接在一起的两个范围之间的随机数输出

这个问题是关于在一个范围之间生成随机数,这很好,但不适合我的情况。

我将用 SQL 术语进行解释,因为在我看来这更容易理解,尽管问题是关于bash.我的想法是用代码的结果bash构建一个SQL脚本。

我有两张 MySQL 表,一张是people,一张是places。每条记录都有一个唯一的整数 ID,范围为 1 到 139(地点)和 1 到 1519(人)。它们通过外键相互联系,意思是:一个地方可以有很多人,但一个人只能有一个地方。

# 1-139  # 1-1519
place1 → person1
       → person2
       → person3
       ... and so on

我现在拥有的数据是在一个地方全部人民是有联系的,而其他地方则没有联系。

名额有139个,人数有1519人,所以我有1个名额,有1519人。

我的目标是将人员随机分配到各个地方,并且每个地方至少有一个人。

到目前为止我的代码是这样的:

$ c=1519
$ while [[ $c -ne 0 ]]; do 
    x=$((shuf -i 1-139 -n 1))
    [[ $x -gt 139 ]] && continue
    echo $x
    (( c-- ))
  done

此代码生成 1-139 之间的 1519 个随机数,因此现在我可以将每个人链接到一个随机位置。

我的问题是:

  • 有没有更有效的方法来实现这一目标?
  • 如何控制每个地方至少有一个人?

我更喜欢在 中执行此操作bash,但我对不涉及它的其他解决方案持开放态度。

答案1

如果您只想使用常用工具(至少在 Linux 发行版上)来执行此操作,最有效的方法可能是询问shuf

shuf -i 1-139 -n 1519 -r

这会产生 1519 个在 1 到 139 之间随机选择的数字。

为保证每个地方都有一个人,先将139个数字洗乱,不要重复:

shuf -i 1-139
shuf -i 1-139 -n 1380 -r

为了减少“前 139 人”效应(前 139 人最终都会在不同的地方),请再次洗牌:

(shuf -i 1-139; shuf -i 1-139 -n 1380 -r) | shuf

答案2

假设表中存储了人员person,并且每个人员都有place_id一个 1 到 139 之间的整数。使用 SQL,person直接更新表:

UPDATE person SET place_id = FLOOR(RAND()*139 + 1);

这应该更新表中的每个条目,随机化place_id密钥。但它完全未经测试。

更新后,您可以使用以下方法测试每个地点是否代表

SELECT COUNT(DISTINCT place_id) = 139 FROM person;

如果所有地点都已表示,则应返回1,否则返回0

答案3

如果我们希望这些值为尽可能均匀分布(考虑到 1519 比 139 的精确倍数少 10),而不是仅仅避免空位,那么我们应该生成一个足够大的重复序列 1, ..., 139, 1, ... , 139, 1, ...,然后对其中的前 1519 个成员进行洗牌:

while seq 139; do :; done | head -n 1519 | shuf

如果我们需要将人物映射到地点,那么我们可以简单地对输出行进行编号:

while seq 139; do :; done | head -n 1519 | shuf | nl

注意,这是所有标准外壳;不需要任何 Bash 扩展。

相关内容