使用 bash 从给定范围创建随机连续数字序列
Using bash to create random contiguous number sequences from a given range
使用给定的值范围,我试图生成三个连续数字的随机实例。
例如,给定范围 1-100
,并希望三个连续数字的三个(非重叠)随机实例,输出将类似于:
4 5 6
50 51 52
32 33 34
我一直在尝试使用命令 shuf
,例如
shuf -i 1-100 -n 3
但这似乎不允许生成随机的连续数字序列。有任何想法吗?
基本答案是从 1 .. (100 - 3 + 1) 或 1..98 范围内生成三个独立的随机值,然后从每个值 n 生成 n、n+1、n+2 .
这只剩下不重叠的要求。需要测试三个数中任意两个数的差距绝对值至少为3;如果不是,则生成一个新号码。您需要决定是否可以生成(假设 'random generation' 生成了 {1, 4, 7} 的排列):
1 2 3
4 5 6
7 8 9
或者数字组之间是否一定要有间隔。如果必须存在间隙,则检查生成值对之间的距离是否至少为 4,而不是 3。
选择要求 3 个值的集合之间至少有一个差距,我最终得到了这个脚本:
#!/bin/bash
min=1 # Minimum value
max=100 # Maximum value
adj=3 # Number of adjacent values per set
num=3 # Number of sets
r_min=$min
r_max=$(($max - $adj + 1))
base=()
while [ ${#base[*]} -lt $num ]
do
next=$(($RANDOM % ($r_max - $r_min + 1) + $r_min))
ok=yes
for n in ${base[@]}
do
gap=$(($next - $n))
[ $gap -lt 0 ] && gap=$((- $gap))
if [ $gap -le $adj ]
then ok=no; break
fi
done
if [ $ok = yes ]
then base+=( $next )
fi
done
for n in ${base[@]}
do
for ((i = 0; i < $adj; i++))
do printf "%4d" $(($n + $i))
done
echo
done
请注意,如果点的集合数和集合中的点数(代码中的$num
和$adj
)变得太大,您可能会陷入无限循环因为没有足够的可能性。例如,$adj
为 3,将 $num
设置为 25 或更多可保证无限循环;不过,在此之前的很长一段时间内,您很容易 运行 陷入麻烦。
示例 运行s:
$ bash randcont.sh
16 17 18
92 93 94
6 7 8
$ bash randcont.sh
81 82 83
40 41 42
13 14 15
$ bash randcont.sh
61 62 63
71 72 73
23 24 25
$ bash randcont.sh
54 55 56
7 8 9
46 47 48
$
用于生成随机数的机制存在偏差——偏向于较低的数字。如果这是个问题,您也可以找出解决方法。
我不认为这是最好的方法;可能有一些方法可以减少蛮力和无知。但它确实 'OK' 满足样本要求。
可以统一生成三元组,而无需测试和拒绝重叠。
问题简化为找到大小为 k {a1 的随机序列... ak} 从 {1…N−2 } 这样子序列的任意两个值之间的最小差值至少为 3。(N−2 因为选择的值是每个三元组的第一个值,所以最大的不能大于比 N−2.)
这可以通过从随机排序的子序列开始来完成 {a'1…a'k} 从 {1…N−((k−1)×2+2)} 然后设置每个 ai 到a'i+2(i−1) .最后,序列可以随机打乱。
这可以很容易地概括为找到大小为 m 的元组。
在bash中:
# tuples n k m
tuples () {
local -i n=${1:-100} k=${2:-3} m=$((${3:-3}-1))
if ((n < k*m + k)); then return 1; fi
local -i i=0 a
for a in $(shuf -i 1-$((n - k * m)) -n $k | sort -n); do
# -s' ' to work around a bug in coreutils 8.20 and 8.21
seq -s' ' $((a+i)) $((a+i+m))
i+=m
done | shuf
}
使用给定的值范围,我试图生成三个连续数字的随机实例。
例如,给定范围 1-100
,并希望三个连续数字的三个(非重叠)随机实例,输出将类似于:
4 5 6
50 51 52
32 33 34
我一直在尝试使用命令 shuf
,例如
shuf -i 1-100 -n 3
但这似乎不允许生成随机的连续数字序列。有任何想法吗?
基本答案是从 1 .. (100 - 3 + 1) 或 1..98 范围内生成三个独立的随机值,然后从每个值 n 生成 n、n+1、n+2 .
这只剩下不重叠的要求。需要测试三个数中任意两个数的差距绝对值至少为3;如果不是,则生成一个新号码。您需要决定是否可以生成(假设 'random generation' 生成了 {1, 4, 7} 的排列):
1 2 3
4 5 6
7 8 9
或者数字组之间是否一定要有间隔。如果必须存在间隙,则检查生成值对之间的距离是否至少为 4,而不是 3。
选择要求 3 个值的集合之间至少有一个差距,我最终得到了这个脚本:
#!/bin/bash
min=1 # Minimum value
max=100 # Maximum value
adj=3 # Number of adjacent values per set
num=3 # Number of sets
r_min=$min
r_max=$(($max - $adj + 1))
base=()
while [ ${#base[*]} -lt $num ]
do
next=$(($RANDOM % ($r_max - $r_min + 1) + $r_min))
ok=yes
for n in ${base[@]}
do
gap=$(($next - $n))
[ $gap -lt 0 ] && gap=$((- $gap))
if [ $gap -le $adj ]
then ok=no; break
fi
done
if [ $ok = yes ]
then base+=( $next )
fi
done
for n in ${base[@]}
do
for ((i = 0; i < $adj; i++))
do printf "%4d" $(($n + $i))
done
echo
done
请注意,如果点的集合数和集合中的点数(代码中的$num
和$adj
)变得太大,您可能会陷入无限循环因为没有足够的可能性。例如,$adj
为 3,将 $num
设置为 25 或更多可保证无限循环;不过,在此之前的很长一段时间内,您很容易 运行 陷入麻烦。
示例 运行s:
$ bash randcont.sh
16 17 18
92 93 94
6 7 8
$ bash randcont.sh
81 82 83
40 41 42
13 14 15
$ bash randcont.sh
61 62 63
71 72 73
23 24 25
$ bash randcont.sh
54 55 56
7 8 9
46 47 48
$
用于生成随机数的机制存在偏差——偏向于较低的数字。如果这是个问题,您也可以找出解决方法。
我不认为这是最好的方法;可能有一些方法可以减少蛮力和无知。但它确实 'OK' 满足样本要求。
可以统一生成三元组,而无需测试和拒绝重叠。
问题简化为找到大小为 k {a1 的随机序列... ak} 从 {1…N−2 } 这样子序列的任意两个值之间的最小差值至少为 3。(N−2 因为选择的值是每个三元组的第一个值,所以最大的不能大于比 N−2.)
这可以通过从随机排序的子序列开始来完成 {a'1…a'k} 从 {1…N−((k−1)×2+2)} 然后设置每个 ai 到a'i+2(i−1) .最后,序列可以随机打乱。
这可以很容易地概括为找到大小为 m 的元组。
在bash中:
# tuples n k m
tuples () {
local -i n=${1:-100} k=${2:-3} m=$((${3:-3}-1))
if ((n < k*m + k)); then return 1; fi
local -i i=0 a
for a in $(shuf -i 1-$((n - k * m)) -n $k | sort -n); do
# -s' ' to work around a bug in coreutils 8.20 and 8.21
seq -s' ' $((a+i)) $((a+i+m))
i+=m
done | shuf
}