从 bash 数组中提取 x 个随机值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6859249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 00:28:41  来源:igfitidea点击:

Extracting x random values from a bash array

arraysbash

提问by Rsaesha

I have an array in Bash, say it contains the numbers {1, 2, 3, 4, 5}. I want to extract some of those numbers randomly, such that the same number doesn't get extracted twice.

我在 Bash 中有一个数组,假设它包含数字 {1, 2, 3, 4, 5}。我想随机提取其中一些数字,这样相同的数字就不会被提取两次。

Basically, if I wanted to extract 3 numbers from the array, I want results like: {3, 4, 1} or {5, 2, 4} and not {1, 1, 3} or {2, 5, 2}.

基本上,如果我想从数组中提取 3 个数字,我想要的结果是:{3, 4, 1} 或 {5, 2, 4} 而不是 {1, 1, 3} 或 {2, 5, 2} .

I've tried deleting elements as I extract them, but it always seems to mess up. Can anyone help?

我试过在提取元素时删除它们,但它似乎总是一团糟。任何人都可以帮忙吗?

回答by Anders Lindahl

Decided to write an answer, as I found the --input-rangeoption to shufthat turned out handy:

决定写一个答案,因为我发现这个--input-range选项shuf很方便:

N=3
ARRAY=( zero one two three four five )

for index in $(shuf --input-range=0-$(( ${#ARRAY[*]} - 1 )) -n ${N})
do
    echo ${ARRAY[$index]}
done

回答by Matt

How about this:

这个怎么样:

for i in {1..10}; do
    echo $i
done | shuf 

That will return all the numbers. If you only want a specific amount, do this:

这将返回所有数字。如果您只想要特定数量,请执行以下操作:

numbers=5    
for i in {1..10}; do
    echo $i
done | shuf | head -$numbers 

And if you want to change the numbers, just change the {1..10}variable to whatever you want.

如果您想更改数字,只需将{1..10}变量更改为您想要的任何值。

回答by mivk

Yet another syntax, still using shuf, and preserving elements with spaces:

另一个语法,仍然使用shuf, 并用空格保留元素:

N=3
ARRAY=( one "two = 2" "3 is three" 4 five )


for el in "${ARRAY[@]}"; do echo $el; done | shuf | head -$N

回答by gniourf_gniourf

This might work for you, if you want a genuine pure bash solution.

如果您想要一个真正的纯 bash 解决方案,这可能对您有用。

takeNrandom() {
# This function takes n+1 parameters: k a1 a2 ... an
# Where k in 0..n
# This function sets the global variable _takeNrandom_out as an array that
# consists of k elements chosen at random among a1 a2 ... an with no repetition
    local k= i
    _takeNrandom_out=()
    shift
    while((k-->0 && $#)); do
        ((i=RANDOM%$#+1))
        _takeNrandom_out+=( "${!i}" )
        set -- "${@:1:i-1}" "${@:i+1}"
    done
}

Try it:

尝试一下:

$ array=( $'a field with\na newline' 'a second field' 'and a third one' 42 )
$ takeNrandom 2 "${array[@]}"
$ declare -p _takeNrandom_out
declare -a _takeNrandom_out='([0]="a second field" [1]="a field with
a newline" [2]="and a third one")'

(the newline is really preserved in the array field).

(换行符确实保留在数组字段中)。

This uses positional parameters, and uses set -- "${@:1:i-1}" "${@:i+1}"to remove the i-th positional parameter. We also used indirect expansion in the line _takeNrandom_out+=( "${!i}" )to have access to the i-th positional parameter.

这使用位置参数,并用于set -- "${@:1:i-1}" "${@:i+1}"删除第i-th 位置参数。我们还在行中使用了间接扩展_takeNrandom_out+=( "${!i}" )来访问i-th 位置参数。

Note.This uses the RANDOMvariable with a modulo, so the distribution is not exactly uniform. It should be fine for arrays with a small number of fields. Anyway if you have a huge array, you probably shouldn't be using Bash in the first place!

笔记。这使用RANDOM带模数的变量,因此分布并不完全均匀。对于具有少量字段的数组应该没问题。无论如何,如果你有一个庞大的数组,你可能一开始就不应该使用 Bash!

回答by RASG

very simple 'oneliner' i like:

非常简单的“oneliner”,我喜欢:

shuf -e ${POOL[@]} -n3

will give you 3 random elements from your $POOLarray

将从您的$POOL数组中为您提供 3 个随机元素

ex:

前任:

#~ POOL=(a b c d e)
#~ shuf -e ${POOL[@]} -n3

d
e
a