Random从数组中选择N个项目并在BASH SCRIPT中更新它

时间:2016-12-30 16:02:45

标签: arrays bash random

我正在尝试随机选择一个数组的项目,然后更新它再次执行直到最后一组:

#! /bin/bash

A=({1..27})
T=${#A[@]} #number of items in the array
N=3 #number of items to be chosen
V=$(($T/$N)) #number of times to loop
echo ${A[@]} " >> ${#A[@]}"
for ((n=0;n<$V;n++)); do 
    A1=()
    for I in `shuf --input-range=0-$(( ${#A[*]} - 1 )) | head -${N}`; do #random chooses N items random
        S=`echo ${A[$I]}` #the chosen items
        #echo $S
        A1+=("$S|") #creates an array with the chosen items 
        A=("${A[@]/$S}") #deletes the the chosen items from array 
    done
    echo ${A[@]} " >> ${#A[@]}"
    echo ${A1[@]} " >> ${#A1[@]}"
done

我使用此代码获得的输出类型是:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27  >> 27
1 4 5 6 7 8 9 10 11 1 1 14 15 16 17 18 19 1 2 4 5 6 7  >> 27
20| 2| 3|  >> 3
4 6 7 8 9 0 1 4 6 7 8 9 2 4 6 7  >> 27
1| | 5|  >> 3
6 7 8 9 0 1 6 7 8 9 2 6 7  >> 27
| | 4|  >> 3
7 8 9 0 1 7 8 9 2 7  >> 27
6| | |  >> 3
7 8 9 0 1 7 8 9 7  >> 27
| | 2|  >> 3
7 9 0 1 7 9 7  >> 27
8| | |  >> 3
7 9 1 7 9 7  >> 27
| | 0|  >> 3
7 9 1 7 9 7  >> 27
| | |  >> 3
1  >> 27
9| 7| |  >> 3

为什么它在开始时工作正常并最终失败的任何想法?

2 个答案:

答案 0 :(得分:1)

你的脚本中有一些错误的东西,特别是你(想你)从数组中删除元素的方式。你没有删除任何元素,你只是用每个字段中的空字符串替换它们的值!。这就是为什么你的数组一直有27个元素,在第一次迭代之后,所有23都从每个字段中删除。这是一个更惯用的脚本:

#! /bin/bash

a=( {1..27} )
n=3 #number of items to be chosen
while ((${#a[@]}>=n)); do
   a1=()
   for ((i=0;i<n;++i)); do
      # pick an index
      x=$((RANDOM%${#a[@]}))
      # append its value to array a1
      a1+=( "${a[x]}" )
      # unset it
      unset 'a[x]'
      # reconstruct array a (make it non-sparse again)
      a=( "${a[@]}" )
   done
   # print array
   printf 'a: %s >> %s\n' "${a[*]}" "${#a[@]}"
   # print chosen elements
   printf 'a1: %s >> %s\n' "${a1[*]}" "${#a1[@]}"
done

答案 1 :(得分:1)

可以对您的脚本进行一些改进:

  1. 使用小写字母
  2. 引用您的扩展("${a[@]}")。
  3. 执行unset a[j]
  4. 删除项目
  5. 使用a=("${a[@]}")重新构建数组。
  6. 不需要头部,因为shuf可以使用-n生成计数结果。
  7. 避免使用反引号,而是使用$(…)
  8. 这会将脚本缩小为:

    #!/bin/bash
    
    t=27                #number of items in the array
    n=3                 #number of items to be chosen
    a=( $(seq 1 "$t") )
    a1=()
    
    while (( ${#a[@]} >= n )); do 
        for j in $(shuf -n "$n" --input-range=0-$((${#a[@]}-1)) ); do # choose $n random items.
            a1+=("${a[j]}")     # append to an array the chosen items.
            unset "a[j]"           # deletes the the chosen items from array.
        done
        a=("${a[@]}")               # re-build the array.
        echo "a  ${a[@]}  >> ${#a[@]}"
        echo "a1 ${a1[@]} >> ${#a1[@]}"
    done
    

    这将产生此输出:

    a  1 2 3 5 6 7 8 9 10 11 12 14 15 16 18 19 20 21 22 23 24 25 26 27  >> 24
    a1 17 13 4 >> 3
    a  1 2 5 6 7 8 10 11 12 14 15 16 18 19 20 21 22 23 24 26 27  >> 21
    a1 17 13 4 25 3 9 >> 6
    a  1 2 5 6 7 8 10 11 14 15 16 18 21 22 23 24 26 27  >> 18
    a1 17 13 4 25 3 9 12 20 19 >> 9
    a  1 2 5 7 8 10 11 14 15 16 21 22 24 26 27  >> 15
    a1 17 13 4 25 3 9 12 20 19 23 6 18 >> 12
    a  2 7 8 10 11 14 15 16 22 24 26 27  >> 12
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 >> 15
    a  2 8 10 14 15 22 24 26 27  >> 9
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 >> 18
    a  2 10 14 24 26 27  >> 6
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 >> 21
    a  14 26 27  >> 3
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 >> 24
    a    >> 0
    a1 17 13 4 25 3 9 12 20 19 23 6 18 1 5 21 7 11 16 22 8 15 2 24 10 14 26 27 >> 27
    

    但是同样的阵列a1可以用shuf一步构建:

    #!/bin/bash
    
    t=27                                # number of items in the array
    n=3                                 # number of items to be chosen
    a1=( $(shuf --input-range=1-"$t") )
    printf '%3s ' "${a1[@]}"; echo
    

    将打印:

    $ ./script.sh 
     15 23  1  9 24  2 21 11 12 10 19 25 27 13  5 26  4  7 14  3 22 20 17 18 16  6  8
    

    或者,如果结果必须是每行$n个元素:

    #!/bin/bash
    
    t=27                                    # number of items in the array
    n=3                                     # number of items to be chosen
    a1=( $(shuf --input-range=1-"$t") )
    
    while ((i+n<=t)); do
        printf '%3s ' "${a1[@]:i:n}"; echo
        ((i+=n))
    done
    

    印刷:

    $ ./script.sh 
      7  19  16 
      4  20  26 
     11  23   2 
     13   6  15 
     22  12  25 
     18  14  10 
     21   8   9 
      5  24  27 
      1   3  17 
    

    看起来更简单的解决方案。