【问题标题】:Using bash to create random contiguous number sequences from a given range使用 bash 从给定范围创建随机连续数字序列
【发布时间】:2015-10-16 05:34:53
【问题描述】:

使用给定的值范围,我试图生成三个连续数字的随机实例。

例如,给定范围1-100,并希望三个连续数字的三个(非重叠)随机实例,输出将类似于:

4 5 6
50 51 52
32 33 34

我一直在尝试使用命令shuf,例如,

shuf -i 1-100 -n 3

但这似乎不允许生成随机连续的数字序列。有任何想法吗?

【问题讨论】:

    标签: bash random shuffle sequential contiguous


    【解决方案1】:

    可以统一生成三元组,而无需测试和拒绝重叠。

    问题归结为找到一个大小为 k {a1...a 的随机序列k} 来自 {1…N-2} 使得子序列的任何两个值之间的最小差至少为 3。 (N -2,因为选择的值是每个三元组的第一个值,所以最大的不能大于N-2。)

    这可以通过从一个随机有序子序列 {a'1...a'k} 从 {1…N−((k−1)×2+2)} 然后设置每个 a em>ia'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
    }
    

    【讨论】:

      【解决方案2】:

      基本答案是从 1 .. (100 - 3 + 1) 或 1..98 范围内生成三个独立的随机值,然后从每个值 n 中生成 n,n+1,n+2。

      这只是给您留下了不重叠的要求。您需要测试三个数字中任意两个之间的差距的绝对值至少为 3;如果没有,则生成一个新号码。您需要决定是否可以生成(假设“随机生成”生成了 {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 或更多可确保无限循环;不过,在那之前的很长一段时间内,您很容易遇到麻烦。

      示例运行:

      $ 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
      $
      

      用于生成随机数的机制存在偏差——偏向于较小的数字。如果这是个问题,您也可以找出解决方法。

      我不相信这是最好的方法;可能有一些方法可以使用较少的蛮力和无知。但它确实在样本要求上“正常”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-20
        • 1970-01-01
        • 2017-12-02
        • 2020-07-12
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多