2011-07-28 46 views
7

Tôi có một mảng trong Bash, nói rằng nó chứa các số {1, 2, 3, 4, 5}. Tôi muốn trích xuất một số những con số một cách ngẫu nhiên, như vậy mà cùng một số không được trích xuất hai lần.Trích xuất x giá trị ngẫu nhiên từ một mảng bash

Về cơ bản, nếu tôi muốn trích xuất 3 số từ mảng, tôi muốn kết quả như: {3, 4, 1} hoặc {5, 2, 4} chứ không phải {1, 1, 3} hoặc {2, 5, 2}.

Tôi đã thử xóa các phần tử khi tôi trích xuất chúng, nhưng nó luôn có vẻ lộn xộn. Có ai giúp được không?

+0

trộn mảng, sau đó chọn n phần tử đầu tiên? Google cho "mảng bash shuffle" tìm thấy một số gợi ý, ví dụ: http://stackoverflow.com/questions/5533569/simple-method-to-shuffle-the-elements-of-an-array-in-bash-shell –

Trả lời

11

Quyết định viết một câu trả lời, như tôi đã tìm thấy các tùy chọn --input-range để shuf rằng hóa ra có ích:

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 
2

Làm thế nào về điều này:

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

Điều đó sẽ trả lại tất cả những con số. Nếu bạn chỉ muốn có một số tiền cụ thể, làm điều này:

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

Và nếu bạn muốn thay đổi các con số, chỉ cần thay đổi {1..10} biến để bất cứ điều gì bạn muốn.

+0

code hoàn toàn hoạt động, nhưng nếu bạn làm 'shuf --input-range 1-10' bạn không cần vòng lặp for để render một tập các chỉ mục mảng. –

1

Tuy nhiên, cú pháp khác, vẫn còn sử dụng shuf, và bảo tồn các yếu tố với các không gian:

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


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

Điều này có thể làm việc cho bạn, nếu bạn muốn có một giải pháp bash tinh khiết chính hãng.

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=$1 i 
    _takeNrandom_out=() 
    shift 
    while((k-->0 && $#)); do 
     ((i=RANDOM%$#+1)) 
     _takeNrandom_out+=("${!i}") 
     set -- "${@:1:i-1}" "${@:i+1}" 
    done 
} 

Thử:

$ 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")' 

(newline thực sự là bảo quản trong lĩnh vực mảng).

Điều này sử dụng thông số vị trí và sử dụng set -- "${@:1:i-1}" "${@:i+1}" để xóa thông số vị trí i -th. Chúng tôi cũng đã sử dụng mở rộng gián tiếp trong dòng _takeNrandom_out+=("${!i}") để có quyền truy cập vào thông số vị trí i -th.

Lưu ý. Điều này sử dụng biến số RANDOM với một modulo, do đó phân phối không chính xác đồng nhất. Nó sẽ là tốt cho mảng với một số lượng nhỏ các lĩnh vực. Dù sao nếu bạn có một mảng lớn, có lẽ bạn không nên sử dụng Bash ngay từ đầu!

Các vấn đề liên quan