Jak losowo wygenerować wyjście z sekwencji?

11

Wiem, że mogę użyć seqdo wygenerowania losowej listy liczb: 1, 2, 3, 4 ...

Chcę uporządkować te liczby w losowej kolejności, takiej jak 3, 1, 4, 2 ...

Wiem, że mogę użyć, shufaby przetasować linie pliku. Więc mógłbym użyć seqdo zapisania losowych liczb w pliku, a następnie użyć ich shufdo losowego losowania - lub napisać jakąś funkcję losowego losowania. Ale wydaje się to niepotrzebnie skomplikowane. Czy istnieje prostszy sposób na randomizację elementów w tablicy za pomocą jednego polecenia?

bernie2436
źródło

Odpowiedzi:

16

Możesz po prostu przesłać dane wyjściowe do potoku shuf.

$ seq 100 | shuf

Przykład

$ seq 10 | shuf
2
6
4
8
1
3
10
7
9
5

Jeśli chcesz, aby wyjście było poziome, podłącz je do niego paste.

$ seq 10 | shuf | paste - -s -d ' '
1 6 9 3 8 4 10 7 2 5 

$ seq 10 | shuf | paste - -s -d ' '
7 4 6 1 8 3 10 5 9 2 

$ seq 10 | shuf | paste - -s -d ' '
9 8 3 6 1 2 10 4 7 5 

Chcesz mieć przecinki między nimi? Zmień separator na paste:

$ seq 10 | shuf | paste - -s -d ','
2,4,9,1,8,7,3,5,10,6
slm
źródło
Ale musisz jakoś sformatować, aby uzyskać je w jednym wierszu z przecinkami. echo $(seq 10 | shuf)zbliża się, ale nie robi przecinków.
mikeserv
Jest poziomy przed paste...
mikeserv
@mikeserv - zmieniłem to.
slm
Tak. Proszę bardzo. Nie wiedziałem, pasteże to zrobiłem. Dzięki za nauczenie mnie. Zyskaj głos.
mikeserv
@mikeserv - tak, przeczytałem stronę, patrząc na moją, Stephane'a lub Gillesa A za pomocą joini paste. Te 2 narzędzia są niezwykle potężne.
slm
3

Czy istnieje prostszy sposób na randomizację elementów w tablicy za pomocą jednego polecenia?

Zakładając, że masz tablicę liczb całkowitych dziesiętnych:

arr=(4 8 14 18 24 29 32 37 42)

Możesz użyć printfi shufdo randomizacji elementów tablicy:

$ arr=($(printf "%d\n" "${arr[@]}" | shuf))
$ echo "${arr[@]}"
4 37 32 14 24 8 29 42 18

(powyższe zakłada, że ​​nie zmodyfikowałeś $IFS).


Jeśli wszystko, czego potrzebujesz, to liczby losowe między dwiema liczbami całkowitymi, powiedzmy 10i 20, nie potrzebujesz żadnych dodatkowych procesów poza shufużyciem -iopcji:

$ shuf -i 10-20
12
10
20
14
16
19
13
11
18
17
15

Cytowanie z man shuf:

   -i, --input-range=LO-HI
          treat each number LO through HI as an input line
diabelnie
źródło
Shucks Też to widziałem, shuf --helpale próbowałem użyć shuf -i 1 10bez ingerencji -dash.no cóż, dobra robota - miej moje poparcie.
mikeserv
2
printf '%s, ' `seq 1 10 | shuf`

Nie potrzebujesz nawet forpętli.

WYNIK

7, 3, 4, 10, 2, 9, 1, 8, 5, 6,

Aby umieścić je w tablicy powłok:

( set -- $(seq 1 10 | shuf) ; printf '%s, ' "$@" )

WYNIK

5, 9, 7, 2, 4, 3, 6, 1, 10, 8,

A potem są w twojej powłoce.

Jeśli umieścisz je w tablicy powłok, nie potrzebujesz nawet printf:

( set -- $(seq 1 10 | shuf); IFS=, ; echo "$*" )

WYNIK

9,4,10,3,1,2,7,5,6,8

Nawiasem mówiąc, seqi printfsą trochę dla siebie stworzeni. Na przykład, jeśli chcę powtórzyć ciąg 1000 razy?

printf 'a string\n%.0b' `seq 1 1000`

WYNIK

a string

... 999 a stringlinii później ...

a string

Lub...

printf 'a string,%.0b' `seq 1 10`

WYNIK

a string,a string,a string,a string,a string,a string,a string,a string,a string,a string,

Chcę wykonać polecenie 39 razy?

printf 'echo "run %d"\n' `seq 1 39` | . /dev/stdin

WYNIK

run 1

... 38 runlinii później ...

run 39
mikeserv
źródło
1

Możesz użyć shufpolecenia, aby losowo wygenerować dane wyjściowe, np

%> for x in $(seq 1 10 | shuf); do echo -n "$x "; done; echo
4 10 8 7 1 6 3 5 2 9 
stokrotka
źródło
1

POSIXly, aby wygenerować przetasowaną listę liczb całkowitych dziesiętnych od mindo max:

awk -v min=1 -v max=10 'BEGIN{
  for (i = min; i <= max; i++) a[i] = i
  srand()
  for (i = min; i <= max; i++) {
    j = int(rand() * (max - min + 1)) + min
    tmp = a[i]; a[i] = a[j]; a[j] = tmp
  }
  for (i = min; i <= max; i++) print a[i]
}'

Uważaj, że przy wielu implementacjach awk, dwukrotne uruchomienie tego polecenia w tej samej sekundzie da ten sam wynik (jako srand()ziarno generatora pseudolosowego na podstawie bieżącego czasu).

Stéphane Chazelas
źródło