Golfe aleatório do dia # 1: embaralhar uma matriz

35

Sobre a série

Estarei executando uma pequena série de desafios de código-golfe que giram em torno do tema da aleatoriedade. Basicamente, este será um campo de golfe de 9 buracos , mas está espalhado por várias perguntas. Você pode participar de qualquer desafio individualmente, como se fosse uma pergunta normal.

No entanto, manterei uma tabela de líderes em todos os desafios. A série terá 9 desafios (por enquanto), um publicado a cada poucos dias. Todo usuário que participa dos nove desafios é elegível para ganhar a série inteira. A pontuação geral deles é a soma dos envios mais curtos em cada desafio (portanto, se você responder a um desafio duas vezes, apenas a melhor resposta será contada na pontuação). Se alguém ocupar o primeiro lugar nesta classificação geral por 28 dias , concederei a eles uma recompensa de 500 representantes .

Embora eu tenha várias idéias alinhadas para a série, os desafios futuros ainda não estão definidos. Se você tiver alguma sugestão, informe-me na postagem da sandbox relevante .

Buraco 1: embaralhar uma matriz

A primeira tarefa é bem simples: dada uma matriz não vazia de números inteiros, embaralhe-a aleatoriamente. Existem algumas regras, porém:

  • Toda permutação possível deve ser retornada com a mesma probabilidade (para que o shuffle tenha uma distribuição uniforme). Você pode verificar se o seu algoritmo é uniforme / imparcial implementando-o em JavaScript no Will it Shuffle , que produzirá uma matriz de vieses - o resultado deve parecer tão uniforme quanto seus Fisher-Yates internos ou classificação (ordem aleatória) .
  • Você não deve usar nenhum método interno ou de terceiros para embaralhar a matriz ou gerar uma permutação aleatória (ou enumerar todas as permutações). Em particular, a única função aleatória interna que você pode usar é obter um único número aleatório de cada vez . Você pode assumir que qualquer método de número aleatório interno é executado em O (1) e é perfeitamente uniforme durante o intervalo solicitado (em um sentido matemático - você pode ignorar detalhes da representação em ponto flutuante aqui). Se o seu idioma permitir que você obtenha uma lista de m números aleatórios de uma só vez, você poderá usar este recurso, desde que os números m sejam independentes um do outro e contados como O (m).
  • Sua implementação não deve exceder uma complexidade de tempo de O (N) , em que N é o tamanho da matriz a ser embaralhada. Por exemplo, você não pode "classificar por números aleatórios".
  • Você pode embaralhar a matriz no lugar ou criar uma nova matriz (nesse caso, a matriz antiga pode ser modificada da maneira que desejar).

Você pode escrever um programa completo ou uma função e receber entradas via STDIN, argumento de linha de comando, argumento de função ou prompt e produzir saída via valor de retorno ou imprimindo em STDOUT (ou alternativa mais próxima). Se você escrever uma função que embaralhe a matriz no lugar, não precisará retorná-la, é claro (desde que o seu idioma permita acessar a matriz modificada após o retorno da função).

A entrada e a saída podem estar em qualquer formato conveniente de lista ou sequência, mas devem suportar números inteiros arbitrários no intervalo -2 31 ≤ x <2 31 . Em princípio, seu código deve funcionar com matrizes de comprimento 2 a 31 , embora isso não precise necessariamente caber em sua memória ou ser concluído dentro de um período de tempo razoável. (Eu só não quero ver limites arbitrários de tamanho para loops de código rígido ou algo assim.)

Isso é código de golfe, então a submissão mais curta (em bytes) vence.

Entre os melhores

O trecho a seguir gerará uma tabela de classificação em todos os desafios da série.

Para garantir que suas respostas sejam exibidas, inicie todas as respostas com um título, usando o seguinte modelo de remarcação:

# Language Name, N bytes

onde Nestá o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(O idioma não é mostrado no momento, mas o snippet exige e o analisa, e eu posso adicionar um cabeçalho por idioma no futuro.)

Martin Ender
fonte
7
Estou decepcionado por não termos permissão para ser "inteligentes" e usar funções de biblioteca que não sejam "obter um número aleatório" . Queremos ver mais 69 implementações de embaralhamento de Fisher-Yates? Por favor, considere remover esta regra em tarefas futuras. Além disso, por que um limite de complexidade de tempo? Por favor, considere relaxá-lo para pelo menos O (n ^ 2); Também acho que alguém pode encontrar uma implementação especialmente eficiente se você permitir O (n!).
precisa saber é
7
@anatolyg A remoção das restrições equivale a todas as respostas sortby(random)(a razão da restrição de tempo) ou simplesmente .shuffle()(a razão da restrição de embutidos), que eu acho muito menos inteligente do que ter que implementar Fisher-Yates ou alguma outra aproximação.
Martin Ender
11
Se você embaralhar no lugar, uma função precisa retornar a matriz ou é suficiente que seja modificada? Posso escrever uma função para em shuffle(array)vez de newArray=shuffle(array)?
Geobits
11
@Bakuriu Afirmar que você pode classificar em tempo linear se os números forem fixos é como afirmar que você pode fazer qualquer coisa em O (1) se os tamanhos de entrada forem fixos. Além disso, a restrição relevante são matrizes de tamanho fixo, não números inteiros de tamanho fixo - porque o tamanho da matriz determina o tamanho que você precisa que seus números aleatórios tenham. De qualquer forma, a limitação da complexidade do tempo é obviamente para o algoritmo geral que você implementa, enquanto os limites dos tamanhos de entrada estão em vigor para que você não precise usar números inteiros de precisão arbitrária se o seu idioma não os usar de imediato .
Martin Ender
2
Por que a solução de Adám está chegando a 43319 bytes, quando na verdade são 14?
Boboquack

Respostas:

20

Dyalog APL, 25 24 bytes

Primeiro para a solução de 25 caracteres: i{⊃a[⍺⍵]←a[⍵⍺]}¨?i←⌽⍳⍴a←⎕

                      a←⎕ ⍝ evaluated input, assign to "a"
                     ⍴a   ⍝ length
                    ⍳⍴a   ⍝ 1 2 .. length
                   ⌽⍳⍴a   ⍝ length .. 2 1
                 i←       ⍝ assign to "i"
                ?i        ⍝ random choices: (1..length)(1..length-1)..(1 2)(1)
i{            }¨?i        ⍝ for each index ⍺ and corresponding random choice ⍵
   a[⍺⍵]←a[⍵⍺]            ⍝ swap a[⍺] and a[⍵]
        ←                 ⍝ in Dyalog, assignment returns its right-hand side
  ⊃                       ⍝ first element, i.e. a[⍵]
                          ⍝ the result from {} is an array of all those a[⍵]

Após algumas transformações de equivalência acima:

i {}¨ ?i  ←→  i {}¨∘? i   ⍝ because A f∘g B ←→ A f g B
          ←→  {}¨∘?⍨ i    ⍝ because f⍨ B ←→ B f B

podemos nos livrar da tarefa i←e salvar um personagem:

{⊃a[⍺⍵]←a[⍵⍺]}¨∘?⍨⌽⍳⍴a←⎕

ngn
fonte
3
... mente. soprado.
214159
11
um idioma que eu tenho que ler da direita para a esquerda ?? Uau!
luminoso
5
@ Luminoso como costuma ser o caso com notação matemática: sin cos ln sqrt x
ngn
4
@ngn quando você coloca dessa maneira que faz o meu comentário anterior parecer ridículo. ha
luminoso
5
@ronalchn Existem codificações de 8 bits para APL, como esta ou esta ; Ouvi dizer que o Dyalog usa um desses, como uma alternativa ao Unicode.
Anatolyg
12

Código de máquina 80386, 44 24 bytes

Hexdump do código:

60 8b fa 0f c7 f0 33 d2 f7 f1 49 8b 04 8f 87 04
97 89 04 8f 75 ed 61 c3

Agradecimentos a FUZxxl, que sugeriu o uso da rdrandinstrução.

Aqui está o código fonte (pode ser compilado pelo Visual Studio):

__declspec(naked) void __fastcall shuffle(unsigned size, int array[])
{
    // fastcall convention:
    // ecx = size
    // edx = array
    _asm
    {
        pushad;             // save registers
        mov edi, edx;       // edi now points to the array

    myloop:
        rdrand eax;         // get a random number
        xor edx, edx;
        div ecx;            // edx = random index in the array

        dec ecx;            // count down
        mov eax, [edi + 4 * ecx];   // swap elements
        xchg eax, [edi + 4 * edx];  // swap elements
        mov [edi + 4 * ecx], eax;   // swap elements
        jnz myloop;

        popad;              // restore registers
        ret;
    }
}

Mais uma implementação de Fisher-Yates. A maior parte do golfe foi alcançada através da passagem de parâmetros nos registros.

anatolyg
fonte
11
Você também poderia ter usado rdrandpara merdas e risadinhas.
FUZxxl
@FUZxxl Eu esqueci completamente! Pena que remove a parte mais interessante sobre a minha resposta ...
anatolyg
9

Java, 88 101

Um embaralhamento básico de Fisher-Yates faz o truque. Sinto que ele será usado com bastante frequência aqui, pois é rápido e fácil de implementar. Há alguns loops / tarefas aqui, mas honestamente não muito para jogar golfe; é apenas curto por natureza.

void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}

Com algumas quebras de linha:

void t(int[]s){
    for(int i=s.length,t,x;
        i>0;
        t=s[x*=Math.random()],
        s[x]=s[i],
        s[i]=t
    )
        x=i--;
}

Isso muda de lugar, modificando a matriz original s[]. Programa de teste:

public class Shuffle {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,5,6,7,8,9};
        new Shuffle().t(a);
        for(int b:a)
            System.out.print(b+" ");
    }
    void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}
}
Geobits
fonte
11
Não, o desafio afirma que você pode assumir que " é perfeitamente uniforme no intervalo solicitado ". O intervalo solicitado Math.random()tem um tamanho que é uma potência de dois, portanto, isso não atende às especificações.
22415 Peter Peter Taylor
11
@PeterTaylor As interpretações de Jan e Geobits são realmente como eu pretendia a regra - que você não precisa se preocupar com a duração real do seu PRNG.
Martin Ender
11
@ MartinBüttner, a duração do ciclo não é o problema aqui - coberto pela sua regra. A grosseria dos carros alegóricos é.
John Dvorak
3
@TheBestOne É um byte menor que a única solução python atualmente postada;)
Geobits 03/02/2015
11
Não mais! : D
Sp3000 04/04
8

Python 2, 86 bytes

from random import*
def S(L):i=len(L);exec"i-=1;j=randint(0,i);L[i],L[j]=L[j],L[i];"*i

Essa é uma função que embaralha a matriz no lugar sem retorná-la, usando uma implementação direta do embaralhamento Fisher-Yates . Obter números aleatórios do Python é caro ...

Obrigado a @xnor e @colevk por dicas.

Sp3000
fonte
Essa expressão de alcance parece bastante complicada. Certamente é mais curto contar manualmente como while i:i-=1;...?
xnor
@ xnor Sim, é - obrigado por isso. Eu continuo esquecendo que whiletende a ser mais curto do que forpara este tipo de coisa ...
SP3000
11
Awww ... agora minha resposta Java não está superando isso. Fiquei muito feliz por um tempo muito curto :(
Geobits 03/02
Você pode salvar outros 2 bytes fazendo i=len(L)e colocando o decremento no início do loop while.
colevk
8

J, 45 44 caracteres

Este foi um assunto complicado.

<@({.,?@#@}.({,<^:3@[{])}.)&>/@(<"0@i.@#,<)

Aqui está uma explicação:

  1. # y: A contagem de y, isto é, o número de elementos emy .
  2. ?@# y: Um número aleatório distribuído uniformemente no intervalo de 1até(#y)-1 .
  3. x { y: O item de y no índice x.
  4. (<<<x) { y: Todos os itens, exceto o item no índice xem y.
  5. x , y: y anexado a x.
  6. x ({ , <^:3@[ { ]) yO item no índice xem y, em seguida, todos os outros itens.
  7. (?@# ({ , <^:3@[ { ]) ]) yUm aleatório y, e todos os outros itens.
  8. x {. y: Os primeiros xitens tomadas a partir y.
  9. x }. y: Os primeiros xitens caiu dey .
  10. x ({. , }.) y: Os primeiros xitens tomadas a partir y, então os primeiros xitens caiu dey
  11. x ({. , (?@# ({ , <^:3@[ { ]) ])@}.) y: Os primeiros xitens tomadas a partir y, então a primeira xitens dey processados tal como no número 7.
  12. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.) y: A mesma coisa com a gota puxada para salvar um personagem.
  13. u/ y: u inserido entre os itens de y.
  14. < y: em y caixa .
  15. <"0 y: Cada item da y caixa .
  16. i. y: números inteiros de 0até y - 1.
  17. i.@# y: números inteiros de 0até (#y) - 1.
  18. (<"0@i.@# , <) y: Números inteiros de 0para (#y) - 1cada caixa e, yem seguida, em uma única caixa. Isso é necessário porque matrizes em J são uniformes. Uma caixa oculta a forma do seu conteúdo.
  19. x u&v y: como (v x) u (v y).
  20. > y: y aberto , ou seja, sem sua caixa.
  21. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&> y a frase do número 12 se aplica a seus argumentos sem caixa.
  22. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/ ya frase do número 21 inserida entre os itens de y.
  23. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/@(<"0@i.@# , <) ya frase do número 22 aplicada ao resultado da frase do número 18 ou uma permutação uniforme dos itens de y.
FUZxxl
fonte
11
Eu simplesmente não consigo distinguir todos os parênteses. E esse boxe triplo <@<@<@[também é um mistério ... Esperando por explicações. :)
randomra
2
Uma vez que este fica explicado, eu poderia ser muito mais provável que upvote esta resposta ;-)
John Dvorak
@randomra Aqui você vai.
FUZxxl
@JanDvorak A explicação é satisfatória?
FUZxxl
Ótima explicação! Eu não sabia sobre todo o uso em caixa de from( {). E eu realmente gosto do &>/truque para manipular uma lista. Tenho certeza de que poderia usá-lo algumas vezes antes.
Aleatório
5

Pitão, 25 bytes

Teste aqui.

Mais uma implementação de Fisher-Yates. É essencialmente o mesmo que a solução python @ Sp3000, apenas em pyth.

FNrlQ1KONJ@QN XXQN@QKKJ)Q

Obrigado a @Jakube pelo truque de troca

<implicit>    Q=input()
FNrlQ1        For N in len(Q) to 1, only goes len Q-1 because how range implemented in pyth
 KON          K = random int 0-N
 J@QN         J=Q[N]
 <space>      Suppress print
 XXQN@QKKJ    Swap K and J
)             End for
Q             Print Q
Maltysen
fonte
Você pode salvar dois bytes combinando essas duas atribuições de lista: `XXQN @ QKKJ` em vez de` XQN @ QK XQKJ`.
Jakube
@Jakube obrigado pela dica. Eu sabia que devia haver uma maneira de trocar valores em uma lista, e isso é realmente inteligente. Você deve adicioná-lo à lista de dicas.
Maltysen 07/04
4

Perl, 68 56 44

Como muitas outras soluções, isso usa o Fisher-Yates algoritmo .

Usando o comentário de nutki , 12 caracteres são salvos usando em $_vez de $ie executando as operações nos índices da matriz.

44:

sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}

56:

sub f{$i=@_;$j=int(rand$i),@_[$i,$j]=@_[$j,$i]while$i--}

Este é o meu primeiro codegolf.

Bonsaigin
fonte
Não é um começo ruim, eu não sabia que você pode usar @_[...]como rvalue assim. Pode ser jogado ainda mais sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}.
nutki
3

C, 63 61 60 bytes

i,t;s(a,m)int*a;{for(;m;a[m]=t)t=a[i=rand()%m--],a[i]=a[m];}

Apenas uma implementação direta do Fischer-Yates que classifica a matriz fornecida no local. Compila e vincula perfeitamente com o compilador visual studio (vs2013, não testou as outras versões) e o compilador Intel. A assinatura da função de aparência agradável és(int array[], int length) . Estou legitimamente impressionado por vencer o Python e o Ruby.

Isso assume que srand()é chamado e rand () é implementado corretamente, mas acredito que esta regra permite isso:

You may assume that any built-in random number method runs in O(1) and is perfectly uniform over the requested interval

Versão bem formatada:

index, temp;
shuffle(array, length) int* array;  {
    for(;length; array[index] = temp)
        index = rand() % length--,
        temp = array[length],
        array[length] = array[index];
}
pseudonym117
fonte
Eu acho que é suficiente fazer o cabeçalho da função s(a,m)*a{, mas não tenho certeza e não quero testar também. Você pode fazer um xorswap, como em a[i]^=a[m]^=a[i]^=a[m]. Isso também evita a necessidade de declarar t.
FUZxxl
@FUZxxl Acredito que uma troca xor cause problemas se i==m.
Geobits
@Geobits de fato. Eu perdi essa possibilidade.
FUZxxl
Eu só estava tentando descobrir por que isso não estava funcionando ... deveria ter lembrado disso. Também preciso s(a,m)int*ado visual studio e do compilador intel. Não tem o gcc ou o clang instalado para testar, mas presumo que eles também irão reclamar.
Pseudonym117
Isso é bastante impressionante. Depois de tentar muitas modificações que não salvaram nada, consegui ver uma maneira de salvar 2 caracteres. Se você alterar a ordem de troca para que a primeira instrução de troca se torne t=a[i], você poderá mover a i=rand()%m--instrução para dentro como o índice da matriz.
precisa saber é o seguinte
3

Oitava, 88 77 bytes

function s=r(s)for(i=length(s):-1:1)t=s(x=randi(i));s(x)=s(i);s(i)=t;end;end

Ainda outra implementação de Fisher-Yates ... Deveria ser bastante direta se eu adicionar os retornos e espaçamentos usuais da linha:

function s=r(s)
  for(i=length(s):-1:1) # Counting down from i to 1
    t=s(x=randi(i));    # randi is builtin number generator for an int from 0 to i
    s(x)=s(i);
    s(i)=t;
  end
end

As palavras-chave "final" realmente matam a pontuação de golfe aqui, infelizmente. Ei, eu posso usar "end" em vez de "endfor" e "endfunction"!

dcsohl
fonte
11
Apenas FYI, os "bytes" não é realmente necessário pelo código, ele apenas garante que não é um título, que contém uma vírgula (para separar a linguagem) e pelo menos um número após a vírgula, e depois é só escolhe a última número que não está riscado. Ter "bytes" ainda é bom. ;)
Martin Ender
11
Você pode economizar 1 byte usando em numelvez de lenght. Como um bônus seu programa também trabalhar com matrizes 2-D aka matrizes;)
paul.oderso
2

Java 8, 77

(x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};

É uma lambda tomando int[] e retornando vazio. Minha primeira tentativa não pareceu muito interessante, então decidi sair lançando uma exceção.

Programa de teste:

interface shuff {
    void shuff(int[] x);
}
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        shuff s = (x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};
        int[] x = {3, 9, 2, 93, 32, 39, 4, 5, 5, 5, 6, 0};
        try {
            s.shuff(x);
        } catch(ArrayIndexOutOfBoundsException _) {}
        for(int a:x) System.out.println(a);
    }
}
feersum
fonte
11
Não é trapaça usar um lambda para se locomover, tendo que escrever uma assinatura de função, quando você precisa fornecer um delegado para usar o lambda em qualquer lugar? Além disso ... você não pode soltar os parênteses Math.random()?
Rawling 04/02
11
@Rawling Você pode votar nesta meta questão . Atualmente, existem 9 votos a favor das lambdas e 0 contra. Sim, os parênteses podem ser removidos.
precisa saber é
Se houver um meta post e um consenso até agora, então disparem. (E desfrutar da pontuação de dois menor golf em mim: p)
Rawling
3
Eu acho que é injusto para a função parar por exceção em um caso normal, é?
Qwertiy
11
@ Qwertiy Cada um na sua ... Você acha injusto, acho ótimo.
feersum
2

Golflua, 37

Como executar o Golflua?

~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$

A entrada é fornecida como uma tabela na variável X. A tabela é embaralhada no lugar.

Exemplo de uso:

> X={0,-45,8,11,2}
> ~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$
> w(T.u(X))
-45 0 8 11 2
mniip
fonte
2

R, 79 bytes

f=function(x){n=length(x);for(i in 1:n){j=sample(i:n,1);x[c(i,j)]=x[c(j,i)]};x}

Esta é uma implementação direta do shuffle de Fisher-Yates. A função R sampledesenha uma amostra aleatória simples de um determinado tamanho de um determinado vetor com igual probabilidade. Aqui estamos desenhando uma amostra aleatória do tamanho 1 em cada iteração a partir dos números inteiros i, ..., n. Como afirmado na pergunta, isso pode ser assumido como O (1); portanto, em toda essa implementação deve ser O (N).

Alex A.
fonte
2

Matlab, 67

Também implementando Fisher-Yates.

a=input('');n=numel(a);for i=1:n;k=randi(i);a([i,k])=a([k,i]);end;a

Achei muito ruim não poder usar a randpermfunção do Matlab . Mas, depois de algumas brincadeiras, pensei em ver a fonte randpermpara ver como isso é feito, e fiquei surpreso ao ver que havia apenas uma linha: [~,p] = sort(rand(1,n))=)

flawr
fonte
2

Perl, 44

sub f{($_[$x],$_)=($_,$_[$x=rand++$i])for@_}

Outro perl em 44 caracteres. Exemplo de uso:

@x=(1..9);f(@x);print@x
nutki
fonte
2

Mathematica, 82 90 83 93 bytes

Nota: Essa variação do embaralhamento de Fisher-Yates é na verdade a solução de Martin Büttner, com algum código aparecendo por alefalpha. sé a matriz de entrada. Nada de sofisticação, mas às vezes as coisas simples são as mais esquivas.

f@s_:=(a=s;m=Length@a;Do[t=a[[r=RandomInteger@{1,m-1}]];a[[r]]=a[[m]]; a[[m]]=t,{n,1,m-1}];a)
DavidC
fonte
Você pode usar Doaqui. É mais curto que While.
Alephalpha
2

Ruby, 57 bytes

->a{a.size.times{|i|j=rand(i+1);a[i],a[j]=a[j],a[i]};p a}

Entrada (como função lambda):

f.([1,2,3,4,5])

Saída:

[2, 1, 4, 3, 5]
Zero Fiber
fonte
2

TI-BASIC, 46 bytes

For(X,dim(L1),2,-1:randInt(1,X→Y:L1(X→Z:L1(Y→L1(X:Z→L1(Y:L1

1   111   2  1111112       1111112 111112 1112 111112 1112

Origem para contagem de bytes

Ypnypn
fonte
11
Você está sentindo falta do End.
lirtosiast
2

K, 31 caracteres

f:{{l[i:x,1?x]:l@|i}'|!#l::x;l}

Não é tão curto quanto o que eu coloquei antes (que foi desclassificado) ... tudo bem.

É um embaralhamento básico de Fisher-Yates. Isso foi construído com muita ajuda da lista de discussão Kona .

kirbyfan64sos
fonte
2

JavaScript (ES6), 66

Essa função embaralha a matriz no lugar. Ele também retorna uma matriz de subprodutos que NÃO é a saída aleatória e não deve ser considerada.

F=a=>a.map((v,i)=>a[a[i]=a[j=0|i+Math.random()*(a.length-i)],j]=v)
edc65
fonte
2

MATL , 16 bytes

XH`HnYr&)XHxvHHn

Experimente online!

Fisher-Yates em MATL. Quase um terço deste programa é dedicado à letra H, que corresponde à função da área de transferência no MATL.

Basicamente, Harmazena os itens não utilizados da entrada, enquanto a pilha controla a lista aleatória.

Sanchises
fonte
2

Japt, 12

rÈiMqZÄ Y}[]

Tente!

-10 (cerca de metade;) graças a @Shaggy!

Eu estava querendo experimentar uma linguagem de golfe, e o intérprete Japt tinha boa documentação e uma maneira de experimentar as coisas no navegador.

Abaixo está a estratégia que tomei:

  • Reduza a propagação de entrada com uma matriz vazia
  • Em cada etapa, encontre um slot aleatório para inserir o elemento atual
dana
fonte
11
Bem-vindo ao Japt, é bom ter você conosco. Eu acho que isso funciona para 9 bytes, usando o mesmo método. Se o RNG não for satisfatório, tente isso .
Shaggy
@ Shaggy - Obrigado pelas dicas! :) Acabei usando uma versão ligeiramente modificada da sua segunda solução. Como o terceiro parâmetro da função de redução é um índice, já sabemos o comprimento.
dana
1

Javascript ES6, 69

a=>{m=a.length;while(m)[a[m],a[i]]=[a[i=~~(Math.random()*m--)],a[m]]}

É o Fisher-Yates.

PS: Pode ser testado no Firefox

Qwertiy
fonte
@ MartinBüttner, removeu :)
Qwertiy
1

Pitão, 27 bytes

Teste aqui

FkQJOhlYaY?@YtJJkIJ XYtJk;Y

Esta é uma implementação do shuffle incremental de Fisher-Yates, mencionado em segundo lugar aqui .

isaacg
fonte
1

Haskell, 170

import System.Random
import Data.Array.IO
s a=do(_,n)<-getBounds a;sequence$map(\i->do j<-randomRIO(i,n);p<-a%i;q<-a%j;writeArray a j p;return q)[1..n]where(%)=readArray

Outra solução Fisher-Yates inspirada no algoritmo em https://wiki.haskell.org/Random_shuffle .

s é uma função que possui assinatura: IOArray Int a -> IO [a]

Jmac
fonte
1

CJam - 30

q~_,,W%{_I=I)mr:J2$=@I@tJ@t}fI

Experimente em http://cjam.aditsu.net/

Exemplo de entrada: [10 20 30 40 50]
Exemplo de saída: 3020401050(adicione a pno final do código para obter uma impressão bonita)

Se o código puder receber a entrada da pilha (como uma função), os 2 primeiros caracteres poderão ser removidos, reduzindo o tamanho para 28.

Explicação:

O código é mais longo do que eu esperava, devido à falta de um operador "swap" para matrizes
(a ser implementado posteriormente: p)

q~            read and evaluate the input (let's call the array "A")
_,,           make an array [0 1 2 ... N-1] where N is the size of A
W%            reverse the array, obtaining [N-1 ... 2 1 0]
{…}fI         for I in this array
    _I=       push A[I]
    I)mr:J    push a random number from 0 to I (inclusive) and store it in J
              stack: A, A[I], J
    2$=       get A[J]
    @I@t      set A[I] = A[J]
              stack: former A[I], A
    J@t       set A[J] = former A[I]
aditsu
fonte
Como mencionado nos comentários, receio que isso seja inválido. No mínimo, _é O (N) (dentro de um loop O (N)). Infelizmente, não vejo uma maneira de contornar isso no CJam.
Martin Ender
As listas são tratadas como objetos imutáveis; portanto, a duplicação é implementada apenas como duplicação da referência. Na verdade, é tisso que mata, já que não pode alterar a lista e agora deve criar uma cópia.
Reader112
@ MartinBüttner Eu estava prestes a postar a mesma coisa que Runer112; sim, pode haver um problema com t, eu gostaria de melhorá-lo em versões futuras ..
aditsu
Portanto, esse código segue o espírito da pergunta, mas não a "letra", devido a problemas de implementação do idioma interno.
Aditsu
1

JavaScript (ES 6), 61

S=a=>(a.map((c,i)=>(a[i]=a[j=Math.random()*++i|0],a[j]=c)),a)

Você pode testá-lo aqui , apenas adicionando uma linha que diz shuffle = S(apenas Firefox).

core1024
fonte
1

STATA, 161

di _r(s)
set ob wordcount($s)
token $s
g a=0
foreach x in $s{
gl j=floor(runiform()*_n)+1
replace a=`$j' if word($s,_n)=`x'
replace a=`x' if word($s,_n)=`$j'
}
l

Espera entrada como números separados por espaço. Posso remover os cabeçalhos e os números de observação da saída, se você quiser, mas, caso contrário, isso é mais curto.

marcações
fonte
O que há _nnisso?
Martin Ender
_n é o número da observação atual.
bmarks
1

Java, 93 bytes

a->{for(int b=0,c,d=0,e=a.length;b<e;c=a[b],a[b]=a[d],a[d]=c,b++,d=b)d+=Math.random()*(e-b);}

Exemplo de uso: http://ideone.com/RqSMnZ

O número um
fonte
1

SQF, 91 bytes

params["i"];{n=floor random count i;i set[_forEachIndex,i select n];i set[n,_x]}forEach i;i
Furioso
fonte
11
Isso é tendencioso (consulte "swap (i <-> aleatório)" em Will It Shuffle), mas você pode transformá-lo em Fisher-Yates (que é imparcial) substituindo %xpor %i.
Martin Ender