这个问题是关于在一个范围之间生成随机数,这很好,但它不适合我的情况。
我将用 SQL 术语进行解释,因为在我看来这更容易理解,尽管问题是关于bash
. 我的想法是用bash
代码的结果构建一个 SQL 脚本。
我有两张 MySQL 表,一张是人,一张是地方。每条记录都有一个唯一的整数 id,从 1 到 139(地点)和 1 到 1519(人)。它们通过外键相互链接,意思是:一个地方可以有很多人,但一个人只能有一个地方。
# 1-139 # 1-1519
place1 → person1
→ person2
→ person3
... and so on
我现在拥有的数据是,在一个地方所有的人都联系在一起,而其他地方没有任何联系。
名额是139,人是1519,所以我有一个地方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
,但我对其他不涉及它的解决方案持开放态度。
如果您只想使用常用工具(至少在 Linux 发行版上)执行此操作,最有效的方法可能是询问
shuf
:这会产生 1519 个在 1 到 139 之间随机选择的数字。
为确保每个地方都有一个人,先洗139个号码,不要重复:
为了减少“前 139”效应(前 139 人最终会在不同的地方),再次洗牌:
假设人员存储在
person
表中,并且每个人的 aplace_id
必须是 1 到 139 之间的整数。使用 SQL,person
直接更新表:这应该更新表中的每个条目,随机化
place_id
密钥。虽然它完全未经测试。更新后,您可以测试每个地方是否通过使用来表示
如果所有地方都被表示,这应该返回
1
,否则返回0
。如果我们希望值尽可能均匀分布(考虑到 1519 比 139 的精确倍数少 10 倍),而不是仅仅避免空位,那么我们应该生成一个足够大的重复序列1, ..., 139, 1, ..., 139, 1, ...,然后将其前 1519 个成员洗牌:
如果我们需要人到地点的映射,那么我们可以简单地对输出行进行编号:
注意这是所有标准外壳;不需要任何 Bash 扩展。