从 Bash 数组中删除随机元素
Deleting random elements from a Bash array
我正在尝试遍历数组并动态选择一个随机元素来取消设置。我尝试了以下内容:
a=('red' 'green' 'black' 'yellow' 'white' 'orange' 'blue' 'purple')
while [ ${#a[@]} -ne 0 ]
do
echo "Length of array:" ${#a[@]}
randomnumber=$(( ( RANDOM % (${#a[@]}) ) ))
echo "random number "$randomnumber" -> "${a[$randomnumber]}
unset a[$randomnumber]
done
每个循环的长度似乎都是正确的,但是当我访问一个之前未设置索引的元素时,内容是空的。我读了一些关于 subshell 的内容,但不知道这意味着什么。 unset 真的会重新排列数组吗?有人可以提示我如何解决这个问题吗?
摘自 bash 的联机帮助页。
The unset builtin is used to destroy arrays. unset name[subscript]
destroys the array element at index subscript. Care must be taken to
avoid unwanted side effects caused by pathname expansion. unset name,
where name is an array, or unset name[subscript], where subscript is *
or @, removes the entire array.
所以取消设置会破坏数组元素。在内存中这可能只是一个指针移动。
更新: 看看这个。由于不删除引用并以某种方式更新数组长度,它似乎缺少 $RANDOM returns 始终是 0 和当前长度之间的数字。
Length of array: 8
8 random number 7 -> purple
Length of array: 7
7 random number 6 -> blue
Length of array: 6
6 random number 2 -> black
Length of array: 5
5 random number 2 ->
Length of array: 5
5 random number 0 -> red
一个可能的解决方案是覆盖数组。
更新: 如果您根据初始长度取消设置尚未取消设置的数组元素,则长度只会改变。所以你 运行 进入无限循环,如果你删除元素 1,那么长度是 7 但是你不能再产生随机数 8 了。所以长度至少为 1.
您需要始终生成 0 到 8 之间的随机数。此外,您可以存储已删除的索引。
length=${#a[@]} # ADD
while [ ${#a[@]} -ne 0 ]
do
echo "Length of array:" ${#a[@]}
randomnumber=$(( $RANDOM % ${#a[@]} )) # if using this arrange the index afterwards like Cyrus said, avoids the overhead mentioned below
#randomnumber=$(( $RANDOM % $length )) # regard initial length
echo "random number "$randomnumber" -> "${a[$randomnumber]}
unset a[$randomnumber]
a=(${a[@]}) # rearranges the indexes
sleep 2
done
如果您不考虑已删除的索引,至少会有一些开销 selecting/creating 已取消设置的索引的随机数。如果 $RANDOM 生成不能正常运行并且不 return 一个范围内的数字,那么无限循环仍然是可能的。这种行为随着数组的长度而增加。
无论如何,这是一个很棒的问题:)
如果取消设置元素 2,则元素 3 不是新元素 2。
# define your array as example
a=('red' 'green' 'black' 'yellow' 'white' 'orange' 'blue' 'purple')
# show array with index in declare's style
declare -p a
输出:
declare -a a='([0]="red" [1]="green" [2]="black" [3]="yellow" [4]="white" [5]="orange" [6]="blue" [7]="purple")'
# remove element 2 (black)
unset a[2]
declare -p a
输出(无元素2):
declare -a a='([0]="red" [1]="green" [3]="yellow" [4]="white" [5]="orange" [6]="blue" [7]="purple")'
可能的解决方案:copy array 重新排列索引:
a=("${a[@]}")
declare -p a
输出:
declare -a a='([0]="red" [1]="green" [2]="yellow" [3]="white" [4]="orange" [5]="blue" [6]="purple")'
我正在尝试遍历数组并动态选择一个随机元素来取消设置。我尝试了以下内容:
a=('red' 'green' 'black' 'yellow' 'white' 'orange' 'blue' 'purple')
while [ ${#a[@]} -ne 0 ]
do
echo "Length of array:" ${#a[@]}
randomnumber=$(( ( RANDOM % (${#a[@]}) ) ))
echo "random number "$randomnumber" -> "${a[$randomnumber]}
unset a[$randomnumber]
done
每个循环的长度似乎都是正确的,但是当我访问一个之前未设置索引的元素时,内容是空的。我读了一些关于 subshell 的内容,但不知道这意味着什么。 unset 真的会重新排列数组吗?有人可以提示我如何解决这个问题吗?
摘自 bash 的联机帮助页。
The unset builtin is used to destroy arrays. unset name[subscript]
destroys the array element at index subscript. Care must be taken to
avoid unwanted side effects caused by pathname expansion. unset name,
where name is an array, or unset name[subscript], where subscript is *
or @, removes the entire array.
所以取消设置会破坏数组元素。在内存中这可能只是一个指针移动。
更新: 看看这个。由于不删除引用并以某种方式更新数组长度,它似乎缺少 $RANDOM returns 始终是 0 和当前长度之间的数字。
Length of array: 8
8 random number 7 -> purple
Length of array: 7
7 random number 6 -> blue
Length of array: 6
6 random number 2 -> black
Length of array: 5
5 random number 2 ->
Length of array: 5
5 random number 0 -> red
一个可能的解决方案是覆盖数组。
更新: 如果您根据初始长度取消设置尚未取消设置的数组元素,则长度只会改变。所以你 运行 进入无限循环,如果你删除元素 1,那么长度是 7 但是你不能再产生随机数 8 了。所以长度至少为 1.
您需要始终生成 0 到 8 之间的随机数。此外,您可以存储已删除的索引。
length=${#a[@]} # ADD
while [ ${#a[@]} -ne 0 ]
do
echo "Length of array:" ${#a[@]}
randomnumber=$(( $RANDOM % ${#a[@]} )) # if using this arrange the index afterwards like Cyrus said, avoids the overhead mentioned below
#randomnumber=$(( $RANDOM % $length )) # regard initial length
echo "random number "$randomnumber" -> "${a[$randomnumber]}
unset a[$randomnumber]
a=(${a[@]}) # rearranges the indexes
sleep 2
done
如果您不考虑已删除的索引,至少会有一些开销 selecting/creating 已取消设置的索引的随机数。如果 $RANDOM 生成不能正常运行并且不 return 一个范围内的数字,那么无限循环仍然是可能的。这种行为随着数组的长度而增加。
无论如何,这是一个很棒的问题:)
如果取消设置元素 2,则元素 3 不是新元素 2。
# define your array as example
a=('red' 'green' 'black' 'yellow' 'white' 'orange' 'blue' 'purple')
# show array with index in declare's style
declare -p a
输出:
declare -a a='([0]="red" [1]="green" [2]="black" [3]="yellow" [4]="white" [5]="orange" [6]="blue" [7]="purple")'
# remove element 2 (black)
unset a[2]
declare -p a
输出(无元素2):
declare -a a='([0]="red" [1]="green" [3]="yellow" [4]="white" [5]="orange" [6]="blue" [7]="purple")'
可能的解决方案:copy array 重新排列索引:
a=("${a[@]}")
declare -p a
输出:
declare -a a='([0]="red" [1]="green" [2]="yellow" [3]="white" [4]="orange" [5]="blue" [6]="purple")'