Sim, existem outras respostas legais nessa pergunta original também.
Ruggiero Spearman
então, você estava fazendo uma lista de palavras wpa? (apenas um palpite aleatório)
thahgr
Respostas:
360
Você pode usar shuf. Em alguns sistemas, pelo menos (não parece estar no POSIX).
Como jleedev apontou: sort -Rtambém pode ser uma opção. Em alguns sistemas, pelo menos; bem, você entendeu. Foi apontado que sort -R, na verdade, não se embaralha, mas ordena os itens de acordo com seu valor de hash.
[Nota do editor: sort -Rquase embaralha, exceto que linhas duplicadas / teclas de classificação sempre terminam próximas uma da outra . Em outras palavras: somente com linhas / teclas de entrada exclusivas, é uma verdadeira reprodução aleatória. Embora seja verdade que a ordem de saída é determinada por valores de hash , a aleatoriedade vem da escolha de uma função de hash aleatória - consulte o manual .]
shufe sort -Rdiferem um pouco, porque sort -Rordena aleatoriamente os elementos de acordo com o hash deles, ou seja, sort -Rreunirá os elementos repetidos, enquanto shufembaralha todos os elementos aleatoriamente.
SeMeKh 28/08/12
146
Para usuários do OS X brew install coreutilsgshuf ...
:,
15
sort -Re shufdeve ser visto como completamente diferente. sort -Ré determinístico. Se você ligar duas vezes em horários diferentes na mesma entrada, obterá a mesma resposta. shuf, por outro lado, produz saída aleatória; portanto, provavelmente fornecerá saída diferente na mesma entrada.
EfForEffort
18
Isso não é correto. "sort -R" usa uma chave de hash aleatória diferente toda vez que você a invoca, portanto produz uma saída diferente a cada vez.
Mark Pettit
3
Nota sobre aleatoriedade: de acordo com a documentação do GNU, "Por padrão, esses comandos usam um gerador pseudo-aleatório interno inicializado por uma pequena quantidade de entropia, mas podem ser direcionados para usar uma fonte externa com a opção --random-source = file."
Royce Williams
85
O one-liner do Perl seria uma versão simples da solução da Maxim
Este foi o único script nesta página que retornou linhas aleatórias REAIS. Outras soluções awk geralmente imprimem saída duplicada.
Felipe Alvarez
1
Mas tenha cuidado porque no fora você vai perder uma linha :) Ela só vai se juntar com outra linha :)
JavaRunner
@JavaRunner: Presumo que você esteja falando de entrada sem deixar rasto \n; sim, isso \ndeve estar presente - e normalmente é - caso contrário, você obterá o que descreve.
mklement0
1
Maravilhosamente conciso. Sugiro substituir <STDIN>por <>, para que a solução funcione com a entrada de arquivos também.
mklement0
60
Esta resposta complementa as muitas ótimas respostas existentes das seguintes maneiras:
As respostas existentes são empacotadas em funções de shell flexíveis :
As funções recebem não apenas stdinentrada, mas também argumentos de nome de arquivo
As funções tomam medidas extras para lidar SIGPIPEda maneira usual (terminação silenciosa com código de saída 141), em vez de quebrar ruidosamente. Isso é importante ao canalizar a saída da função para um tubo que é fechado mais cedo, como ao canalizar head.
Uma comparação de desempenho é feita.
Função compatível com POSIX com base em awk, sortecut adaptada da própria resposta do OP :
shuf(){ python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write("".join(lines))
'"$@";}
Consulte a seção inferior para uma versão do Windows desta função.
Nota: Esses números foram obtidos em um iMac de final de 2012 com Intel Core i5 de 3,2 GHz e um Fusion Drive, executando o OSX 10.10.3. Embora os tempos variem com o SO usado, as especificações da máquina, a awkimplementação usada (por exemplo, a awkversão BSD usada no OSX é geralmente mais lenta que o GNU awke especialmente mawk), isso deve fornecer uma sensação geral de desempenho relativo .
Arquivo de entrada é um arquivo de 1 milhão de linhas produzido com seq -f 'line %.0f' 1000000.
Os horários são listados em ordem crescente (mais rápido primeiro):
shuf
0.090s
Ruby 2.0.0
0.289s
Perl 5.18.2
0.589s
Pitão
1.342scom Python 2.7.6; 2.407s(!) com Python 3.4.2
awk+ sort+cut
3.003scom BSD awk; 2.388scom GNU awk(4.1.1); 1.811scom mawk(1.3.4);
Para uma comparação mais detalhada, as soluções não empacotadas como funções acima:
sort -R (não é uma verdadeira reprodução aleatória se houver linhas de entrada duplicadas)
10.661s - alocar mais memória não parece fazer diferença
Scala
24.229s
bash loops + sort
32.593s
Conclusões :
Use shuf, se puder - é o mais rápido de longe.
Ruby faz bem, seguido por Perl .
O Python é visivelmente mais lento que o Ruby e Perl e, comparando as versões do Python, o 2.7.6 é um pouco mais rápido que o 3.4.1
Use o combo + awk+ compatível com POSIX como último recursosortcut ; qual awkimplementação você usa é importante ( mawké mais rápida que o GNU awk, BSDawk é mais lento).
Fique longe de sort -R, bashloops, e Scala.
Versões do Windows da solução Python (o código Python é idêntico, exceto pelas variações nas citações e pela remoção das instruções relacionadas ao sinal, que não são suportadas no Windows):
Para o PowerShell (no Windows PowerShell, você precisará ajustar $OutputEncodingse desejar enviar caracteres não ASCII por meio do pipeline):
# Call as `shuf someFile.txt` or `Get-Content someFile.txt | shuf`function shuf {
$Input | python -c @'
import sys, random, fileinput;
lines=[line for line in fileinput.input()];
random.shuffle(lines); sys.stdout.write(''.join(lines))
'@ $args
}
Observe que o PowerShell pode embaralhar nativamente por meio de seu Get-Randomcmdlet (embora o desempenho possa ser um problema); por exemplo: Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
Para cmd.exe(um arquivo em lotes):
Salve no arquivo shuf.cmd, por exemplo:
@echo off
python -c "import sys, random, fileinput; lines=[line for line in fileinput.input()]; random.shuffle(lines); sys.stdout.write(''.join(lines))"%*
Não SIGPIPE não existe no Windows, então eu usei este one-liner simples em vez disso:python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
Elig
@elig: Obrigado, mas omitir from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);a solução original é suficiente e mantém a flexibilidade de também ser capaz de passar argumentos de nome de arquivo - não há necessidade de alterar mais nada (exceto citações) - consulte a nova seção que adicionei no inferior.
usar o seguinte comando
27
Eu uso um pequeno script perl, que eu chamo de "unsort":
#!/usr/bin/perl
use List::Util'shuffle';@list=<STDIN>;
print shuffle(@list);
Eu também tenho uma versão delimitada por NULL, chamada "unsort0" ... útil para usar com o find -print0 e assim por diante.
PS: Votado como 'shuf' também, eu não fazia ideia de que existia no coreutils hoje em dia ... o acima pode ainda ser útil se o seu sistema não tiver 'shuf'.
Bem feito; Sugiro substituir <STDIN>por <>para que a solução funcione com a entrada de arquivos também.
Mklement0
20
Aqui está uma primeira tentativa que é fácil no codificador, mas difícil na CPU, que acrescenta um número aleatório a cada linha, classifica-os e retira o número aleatório de cada linha. Com efeito, as linhas são classificadas aleatoriamente:
Certo, eu depuro com head myfile | awk .... Então eu apenas mudo para gato; por isso foi deixado lá.
Ruggiero Spearman
Não é necessário -k1 -nclassificar, pois a saída do awk's rand()é um decimal entre 0 e 1 e porque tudo o que importa é que ele é reordenado de alguma forma. -k1pode ajudar a acelerar, ignorando o restante da linha, embora a saída de rand () deva ser exclusiva o suficiente para causar um curto-circuito na comparação.
bonsaiviking
@ ghostdog74: A maioria dos chamados usos inúteis do gato é realmente útil por ser consistente entre os comandos canalizados e não. É melhor manter o cat filename |(ou < filename |) do que lembrar como cada programa recebe a entrada do arquivo (ou não).
Bem feito, mas na prática muito mais lento que a resposta do OP , que combina awkcom sorte cut. Por não mais do que vários milhares de linhas, isso não faz muita diferença, mas com contagens mais altas isso importa (o limite depende da awkimplementação usada). Uma ligeira simplificação seria substituir as linhas while (1){e if (e==d) {break}por while (e<d).
a "desvantagem" não é específica para o Python. Períodos finitos de PRNG podem ser contornados, realimentando o PRNG com a entropia do sistema, como /dev/urandomfaz. Para utilizá-lo a partir de Python: random.SystemRandom().shuffle(L).
jfs
o join () não precisa estar em '\ n' para que as linhas sejam impressas cada uma por si?
elegível
@elig: Não, porque .readLines()retorna as linhas com uma nova linha à direita.
Isso deve funcionar em quase qualquer UNIX. Testado em Linux, Solaris e HP-UX.
Atualizar:
Observe que zeros à esquerda ( %06d) e rand()multiplicação fazem com que funcione corretamente também em sistemas onde sortnão entende números. Ele pode ser classificado por ordem lexicográfica (também conhecida como comparação normal de cadeias).
Boa idéia para empacotar a resposta do próprio OP como uma função; se você anexar "$@", também funcionará com os arquivos como entrada. Não há motivo para multiplicar rand(), porque sort -né capaz de ordenar frações decimais. É, no entanto, uma boa idéia para controle de awkformato de saída 's, porque com o formato padrão, %.6g, rand()saída vontade o número ocasional nas exponencial notação. Embora a prática de embaralhar até 1 milhão de linhas seja discutível o suficiente na prática, é fácil oferecer suporte a mais linhas sem pagar muita penalidade de desempenho; por exemplo %.17f.
mklement0
1
@ mklement0 Não notei a resposta do OP ao escrever o meu. rand () é multiplicado por 10e6 para fazê-lo funcionar com a classificação solaris ou hpux, tanto quanto me lembro. Boa idéia com "$ @"
Michał Šrajer
1
Entendi, obrigado; talvez você possa adicionar essa lógica da multiplicação à própria resposta; geralmente, de acordo com o POSIX, sortdeve ser capaz de lidar com frações decimais (mesmo com milhares de separadores, como acabei de notar).
Coisas boas; Se você usar puts ARGF.readlines.shuffle, poderá fazê-lo funcionar com os argumentos stdin input e filename.
mklement0
Ainda mais curto ruby -e 'puts $<.sort_by{rand}'- o ARGF já é um enumerável, para que possamos embaralhar as linhas classificando-as por valores aleatórios.
akuhn
6
Um liner para Python com base na resposta do scai , mas a) pega stdin, b) torna o resultado repetível com a semente, c) escolhe apenas 200 de todas as linhas.
Este é um script python que salvei como rand.py na minha pasta pessoal:
#!/bin/python
import sys
import random
if __name__ =='__main__':
with open(sys.argv[1],'r') as f:
flist = f.readlines()
random.shuffle(flist)for line in flist:
print line.strip()
No Mac OSX sort -Re shufnão estão disponíveis, você pode usar o alias em seu bash_profile como:
Se, como eu, você veio aqui para procurar uma alternativa shufpara o macOS, use randomize-lines.
Instale o randomize-linespacote (homebrew), que possui um rlcomando com funcionalidade semelhante a shuf.
brew install randomize-lines
Usage: rl [OPTION]...[FILE]...Randomize the lines of a file (or stdin).-c,--count=N select N lines from the file
-r,--reselect lines may be selected multiple times
-o,--output=FILE
send output to file
-d,--delimiter=DELIM
specify line delimiter (one character)-0,--null set line delimiter to null character
(useful with find -print0)-n,--line-number
print line number with output lines
-q,--quiet,--silent
do not output any errors or warnings
-h,--help display this help and exit
-V,--version output version information and exit
Sedutoramente simples, mas, a menos que a Java VM deva ser iniciada de qualquer maneira, esse custo de inicialização é considerável; também não funciona bem com contagens de linhas grandes.
mklement0
1
Esta função bash tem a dependência mínima (somente classificação e bash):
Solução bacana legal que se assemelha à awksolução assistida pelo OP , mas o desempenho será um problema com maior entrada; o uso de um único $RANDOMvalor embaralha corretamente apenas até 32.768 linhas de entrada; Embora você possa estender esse intervalo, provavelmente não vale a pena: por exemplo, na minha máquina, executar seu script em 32.768 linhas curtas de entrada leva cerca de 1 segundo, o que equivale a 150 vezes o tempo que a execução shufdemora e 10 a 15 vezes enquanto a awksolução própria do OP demorar. Se você pode confiar em sortestar presente, awkdeve estar lá também.
mklement0
0
No Windows, você pode tentar este arquivo em lotes para ajudá-lo a embaralhar seus dados.txt. O uso do código em lotes é
C:\> type list.txt | shuffle.bat > maclist_temp.txt
Após emitir este comando, o maclist_temp.txt conterá uma lista aleatória de linhas.
Respostas:
Você pode usar
shuf
. Em alguns sistemas, pelo menos (não parece estar no POSIX).Como jleedev apontou:
sort -R
também pode ser uma opção. Em alguns sistemas, pelo menos; bem, você entendeu. Foi apontado quesort -R
, na verdade, não se embaralha, mas ordena os itens de acordo com seu valor de hash.[Nota do editor:
sort -R
quase embaralha, exceto que linhas duplicadas / teclas de classificação sempre terminam próximas uma da outra . Em outras palavras: somente com linhas / teclas de entrada exclusivas, é uma verdadeira reprodução aleatória. Embora seja verdade que a ordem de saída é determinada por valores de hash , a aleatoriedade vem da escolha de uma função de hash aleatória - consulte o manual .]fonte
shuf
esort -R
diferem um pouco, porquesort -R
ordena aleatoriamente os elementos de acordo com o hash deles, ou seja,sort -R
reunirá os elementos repetidos, enquantoshuf
embaralha todos os elementos aleatoriamente.brew install coreutils
gshuf ...
sort -R
eshuf
deve ser visto como completamente diferente.sort -R
é determinístico. Se você ligar duas vezes em horários diferentes na mesma entrada, obterá a mesma resposta.shuf
, por outro lado, produz saída aleatória; portanto, provavelmente fornecerá saída diferente na mesma entrada.O one-liner do Perl seria uma versão simples da solução da Maxim
fonte
\n
; sim, isso\n
deve estar presente - e normalmente é - caso contrário, você obterá o que descreve.<STDIN>
por<>
, para que a solução funcione com a entrada de arquivos também.Esta resposta complementa as muitas ótimas respostas existentes das seguintes maneiras:
As respostas existentes são empacotadas em funções de shell flexíveis :
stdin
entrada, mas também argumentos de nome de arquivoSIGPIPE
da maneira usual (terminação silenciosa com código de saída141
), em vez de quebrar ruidosamente. Isso é importante ao canalizar a saída da função para um tubo que é fechado mais cedo, como ao canalizarhead
.Uma comparação de desempenho é feita.
awk
,sort
ecut
adaptada da própria resposta do OP :Consulte a seção inferior para uma versão do Windows desta função.
Comparação de desempenho:
Nota: Esses números foram obtidos em um iMac de final de 2012 com Intel Core i5 de 3,2 GHz e um Fusion Drive, executando o OSX 10.10.3. Embora os tempos variem com o SO usado, as especificações da máquina, a
awk
implementação usada (por exemplo, aawk
versão BSD usada no OSX é geralmente mais lenta que o GNUawk
e especialmentemawk
), isso deve fornecer uma sensação geral de desempenho relativo .Arquivo de entrada é um arquivo de 1 milhão de linhas produzido com
seq -f 'line %.0f' 1000000
.Os horários são listados em ordem crescente (mais rápido primeiro):
shuf
0.090s
0.289s
0.589s
1.342s
com Python 2.7.6;2.407s
(!) com Python 3.4.2awk
+sort
+cut
3.003s
com BSDawk
;2.388s
com GNUawk
(4.1.1);1.811s
commawk
(1.3.4);Para uma comparação mais detalhada, as soluções não empacotadas como funções acima:
sort -R
(não é uma verdadeira reprodução aleatória se houver linhas de entrada duplicadas)10.661s
- alocar mais memória não parece fazer diferença24.229s
bash
loops +sort
32.593s
Conclusões :
shuf
, se puder - é o mais rápido de longe.awk
+ compatível com POSIX como último recursosort
cut
; qualawk
implementação você usa é importante (mawk
é mais rápida que o GNUawk
, BSDawk
é mais lento).sort -R
,bash
loops, e Scala.Versões do Windows da solução Python (o código Python é idêntico, exceto pelas variações nas citações e pela remoção das instruções relacionadas ao sinal, que não são suportadas no Windows):
$OutputEncoding
se desejar enviar caracteres não ASCII por meio do pipeline):Observe que o PowerShell pode embaralhar nativamente por meio de seu
Get-Random
cmdlet (embora o desempenho possa ser um problema); por exemplo:Get-Content someFile.txt | Get-Random -Count ([int]::MaxValue)
cmd.exe
(um arquivo em lotes):Salve no arquivo
shuf.cmd
, por exemplo:fonte
python -c "import sys, random; lines = [x for x in sys.stdin.read().splitlines()] ; random.shuffle(lines); print(\"\n\".join([line for line in lines]));"
from signal import signal, SIGPIPE, SIG_DFL; signal(SIGPIPE, SIG_DFL);
a solução original é suficiente e mantém a flexibilidade de também ser capaz de passar argumentos de nome de arquivo - não há necessidade de alterar mais nada (exceto citações) - consulte a nova seção que adicionei no inferior.Eu uso um pequeno script perl, que eu chamo de "unsort":
Eu também tenho uma versão delimitada por NULL, chamada "unsort0" ... útil para usar com o find -print0 e assim por diante.
PS: Votado como 'shuf' também, eu não fazia ideia de que existia no coreutils hoje em dia ... o acima pode ainda ser útil se o seu sistema não tiver 'shuf'.
fonte
<STDIN>
por<>
para que a solução funcione com a entrada de arquivos também.Aqui está uma primeira tentativa que é fácil no codificador, mas difícil na CPU, que acrescenta um número aleatório a cada linha, classifica-os e retira o número aleatório de cada linha. Com efeito, as linhas são classificadas aleatoriamente:
fonte
head myfile | awk ...
. Então eu apenas mudo para gato; por isso foi deixado lá.-k1 -n
classificar, pois a saída do awk'srand()
é um decimal entre 0 e 1 e porque tudo o que importa é que ele é reordenado de alguma forma.-k1
pode ajudar a acelerar, ignorando o restante da linha, embora a saída de rand () deva ser exclusiva o suficiente para causar um curto-circuito na comparação.cat filename |
(ou< filename |
) do que lembrar como cada programa recebe a entrada do arquivo (ou não).aqui está um script awk
resultado
fonte
awk
comsort
ecut
. Por não mais do que vários milhares de linhas, isso não faz muita diferença, mas com contagens mais altas isso importa (o limite depende daawk
implementação usada). Uma ligeira simplificação seria substituir as linhaswhile (1){
eif (e==d) {break}
porwhile (e<d)
.Um one-liner para python:
E para imprimir apenas uma única linha aleatória:
Mas veja este post para as desvantagens do python
random.shuffle()
. Não funcionará bem com muitos elementos (mais de 2080).fonte
/dev/urandom
faz. Para utilizá-lo a partir de Python:random.SystemRandom().shuffle(L)
..readLines()
retorna as linhas com uma nova linha à direita.Função simples baseada em awk fará o trabalho:
uso:
Isso deve funcionar em quase qualquer UNIX. Testado em Linux, Solaris e HP-UX.
Atualizar:
Observe que zeros à esquerda (
%06d
) erand()
multiplicação fazem com que funcione corretamente também em sistemas ondesort
não entende números. Ele pode ser classificado por ordem lexicográfica (também conhecida como comparação normal de cadeias).fonte
"$@"
, também funcionará com os arquivos como entrada. Não há motivo para multiplicarrand()
, porquesort -n
é capaz de ordenar frações decimais. É, no entanto, uma boa idéia para controle deawk
formato de saída 's, porque com o formato padrão,%.6g
,rand()
saída vontade o número ocasional nas exponencial notação. Embora a prática de embaralhar até 1 milhão de linhas seja discutível o suficiente na prática, é fácil oferecer suporte a mais linhas sem pagar muita penalidade de desempenho; por exemplo%.17f
.sort
deve ser capaz de lidar com frações decimais (mesmo com milhares de separadores, como acabei de notar).Ruby FTW:
fonte
puts ARGF.readlines.shuffle
, poderá fazê-lo funcionar com os argumentos stdin input e filename.ruby -e 'puts $<.sort_by{rand}'
- o ARGF já é um enumerável, para que possamos embaralhar as linhas classificando-as por valores aleatórios.Um liner para Python com base na resposta do scai , mas a) pega stdin, b) torna o resultado repetível com a semente, c) escolhe apenas 200 de todas as linhas.
fonte
Uma maneira simples e intuitiva seria usar
shuf
.Exemplo:
Assuma
words.txt
como:Para embaralhar as linhas, faça:
o que jogaria as linhas embaralhadas para a saída padrão ; Então, você deve canalizá- lo para um arquivo de saída como:
Uma dessas execuções aleatórias poderia render:
fonte
Temos um pacote para fazer o mesmo trabalho:
Exemplo:
Crie uma lista ordenada de números e salve-a em 1000.txt:
para embaralhar, basta usar
fonte
Este é um script python que salvei como rand.py na minha pasta pessoal:
No Mac OSX
sort -R
eshuf
não estão disponíveis, você pode usar o alias em seu bash_profile como:fonte
Se, como eu, você veio aqui para procurar uma alternativa
shuf
para o macOS, userandomize-lines
.Instale o
randomize-lines
pacote (homebrew), que possui umrl
comando com funcionalidade semelhante ashuf
.brew install randomize-lines
fonte
brew install coreutils
fornece oshuf
binário comogshuf
.Se você tem o Scala instalado, aqui está uma lista para embaralhar a entrada:
fonte
Esta função bash tem a dependência mínima (somente classificação e bash):
fonte
awk
solução assistida pelo OP , mas o desempenho será um problema com maior entrada; o uso de um único$RANDOM
valor embaralha corretamente apenas até 32.768 linhas de entrada; Embora você possa estender esse intervalo, provavelmente não vale a pena: por exemplo, na minha máquina, executar seu script em 32.768 linhas curtas de entrada leva cerca de 1 segundo, o que equivale a 150 vezes o tempo que a execuçãoshuf
demora e 10 a 15 vezes enquanto aawk
solução própria do OP demorar. Se você pode confiar emsort
estar presente,awk
deve estar lá também.No Windows, você pode tentar este arquivo em lotes para ajudá-lo a embaralhar seus dados.txt. O uso do código em lotes é
Após emitir este comando, o maclist_temp.txt conterá uma lista aleatória de linhas.
Espero que isto ajude.
fonte
Ainda não mencionado:
O
unsort
util. Sintaxe (um pouco orientada para a lista de reprodução):msort
pode embaralhar por linha, mas geralmente é um exagero:fonte
Outra
awk
variante:fonte