Selecionar aleatoriamente em uma matriz


19

Esse desafio é bastante simples:
você recebe uma matriz de números inteiros positivos (sem incluir 0) e precisa selecionar um elemento aleatório nessa matriz.

Mas aqui está a diferença:
a probabilidade de selecionar um elemento depende do valor do número inteiro, ou seja, à medida que o número inteiro aumenta, a probabilidade de ele ser selecionado também!

Exemplo

Você recebe a matriz [4, 1, 5].

A probabilidade de selecionar 4 é igual a 4 dividido pela soma de todos os elementos na matriz , neste caso 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
A probabilidade de selecionar 1 é 1 / 10ou 10%.

Entrada

Uma matriz de números inteiros positivos.

Resultado

Retorne o número inteiro selecionado se estiver usando um método ou imprima-o diretamente para stdout.

Regras

  • Este é o pelo que o código mais curto em bytes em qualquer idioma vence.
  • As brechas padrão são proibidas.

Respostas:


20

Geléia , 3 bytes

x`X

Experimente online!

Olha, não, Unicode!

Explicação:

x`X
 `  Make monad from dyad and use same left and right arguments
x   Repeat each element of the left argument (implicit) list its respective number of times in the right argument list
  X Random element

11
Você pode explicar o que seu código faz, por favor? :)
Ian H.

11
@IanH. É realmente um algoritmo simples, repita cada elemento em si e escolha aleatoriamente.
Erik the Outgolfer

16

R , 25 bytes

function(s)sample(s,1,,s)

Experimente online!

Explicação:

function(s){
 sample(x = s, size = 1, replace = FALSE, prob = s)
}

Retira uma amostra do stamanho 1sem reposição, com pesos s; estes são redimensionados para serem probabilidades.

Para verificar a distribuição, use este link .


você me venceu por 9 meses! : D
JayCe

@ JayCe heh, minha única vantagem sobre você parece estar "indo primeiro", pois você é um jogador de golfe! :-)
Giuseppe

13

Pitão , 4 bytes

OsmR

Experimente aqui.

Salvo um byte, graças a @Jakube, com uma abordagem bastante incomum.

Pitão , 5 bytes

Osm*]

Experimente aqui!

Quão?

# 1

OsmR - Programa completo.

   R - Mapa direito ...
  m - ... Usando o mapa. Isso cria essencialmente a lista [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... O crédito vai para Jakube por isso!
 s - Achatar.
O - Elemento aleatório de ^. Exibir implicitamente.

# 2

Osm *] - Programa completo.

  m - Mapa sobre a entrada.
    ] - O elemento atual, d, empacotado; [d]
   * - D repetidas vezes.
 s - Achatar.
O - Elemento aleatório. Imprima implicitamente o resultado.

11
Posso fazê-lo em 4. Devo estragá-lo ou você deseja encontrá-lo sozinho?
Jakube 14/09

2
@Jakube Espere um pouco. Quero ver se eu consigo. É que óbvio?
Xcoder 14/09

11
@Jakube Ok, vou pingar quando desistir.
Sr. Xcoder 14/17

11
OsmLouOsmR
Jakube 14/09

11
@Jakube Ooh isso é muito inteligente! Argumento implícito d, depois mapeia dem um intervalo ... gênio!
Erik the Outgolfer

8

CJam (9 bytes)

q~_]ze~mR

Demonstração online . Este é um programa completo que recebe entrada no formato de array CJam no stdin e imprime o elemento selecionado no stdout.

Dissecação

q~   e# Read and parse input
_]z  e# Copy and transpose
e~   e# Run-length decode
mR   e# Select random element uniformly

11
Um golfe tão poderoso para uma tarefa tão simples.
Erik the Outgolfer

7

Perl 6 , 20 bytes

Guardou 1 byte graças a @Brad Gilbert b2gills.

{bag(@_ Zxx@_).pick}

Experimente online!

Isso leva 1 argumento da lista. Zipamos duas cópias desta lista usando o xxoperador. Assim @_ Zxx@_, obtemos uma lista na qual o elemento xé apresentado xvezes. Em seguida, ele é coagido Bag, que é uma coleção que armazena objetos e quantas vezes eles aparecem na coleção. Finalmente, escolhemos um elemento aleatório desta coleção com pick, que leva as contagens para a conta e faz The Right Thing ™.


Isso pode ser reduzido para{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills 15/17

@ BradGilbertb2gills, infelizmente isso não funciona. Faz um saco com os pares (então não haveria "1" uma vez, "2" duas vezes etc.), mas "1 => 1" uma vez ", 2 => 2" também uma vez etc. - não é o que eu quero) . Isso ocorre porque os compositores não são coagidores, conforme explicado neste Calendário do Advento .
Ramillies

@ BradGilbertb2gills, mas obrigado de qualquer maneira, você me ajudou a jogar fora alguns espaços aqui e em outros desafios também!
Ramillies

Eu quis dizer{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills 15/09

Aah, entendo. Por que isso não me ocorreu ...: -) Obrigado.
Ramillies 15/09


5

MATL , 8 6 bytes

tY"1Zr

Experimente no MATL Online!

Explicação

t    % Implicit input. Duplicate
Y"   % Run-length decoding
1Zr  % Randomly take one value with uniform distribution. Implicitly display




4

Java (OpenJDK 8) , 88 87 86 83 bytes

a->{int r=0,x=-1;for(int i:a)r-=i;for(r*=Math.random();r<1;)r+=a[++x];return a[x];}

Experimente online!


Você poderia adicionar uma explicação? Estou tentando entender por que for(r*=Math.random();;)é necessário ou se tudo o que você precisa é r*=Math.random().
Ayb4btu

@ Ayb4btu Sem o for(;;)loop, isso exigiria uma segunda declaração de retorno (nunca alcançada) após a for(int i:a)...para satisfazer o compilador - que seria 3 bytes mais longo.
Nevay 15/09

Ah, claro, você for(int i:a)é como um foreachem C #. Eu tive o mesmo problema, mas apenas usei um forque continuamente circula. Sua nova resposta me intriga, posso tentar roubar algumas de suas idéias.
Ayb4btu

3

J, 8 7 8 bytes

O byter 7 é inválido; Vou reverter isso para uma edição anterior quando voltar ao meu computador em um dia ou dois.

Experimente online!

?@+/{#~

:( selecionar elementos aleatórios de uma matriz é caro.

8 bytes

#~{~1?+/

9 bytes

(1?+/){#~

Explicação

?@+/{#~
?        Choose random number in range
  +/     Sum of the array
    {    Select that element from
     #~  The elements duplicated as many times as their value

?@+/é (?@+)/; Eu tenho medo que você terá que aumentar isso até 8 novamente ...
FireFly

@ FireFly Eu deveria ter testado mais, boa captura.
cole

3

JavaScript (ES6), 50 bytes

a=>a.sort((a,b)=>b-a)[Math.random()**2*a.length|0]

Espero que seja aparente como isso funciona, mas eu explicarei aqui de qualquer maneira. Classifica os números inteiros em ordem decrescente e escolhe um aleatoriamente com uma distribuição beta (1 / 2,1) .


Eu não acho que isso terá a distribuição correta. Meus testes mostram que, com a=[4,1,5], você terá cerca de 18% 1, 24% 4e 58% 5, o que sugere que você vai ter que a distribuição com qualquer entrada de comprimento 3.
Giuseppe

Isso parece correto para mim. Inteiro maior, maior probabilidade.
kamoroso94

Ah eu vejo. Eu interpretei mal a pergunta. Excelente solução, +1!
Giuseppe


2

PowerShell , 27 bytes

($args[0]|%{,$_*$_})|Random

Experimente online!

Recebe entrada $args[0]como uma matriz literal. Os loops através de cada elemento |%{...}e cada iteração constroem uma nova matriz ,$_de $_elementos - por exemplo, para 4isso criará uma matriz @(4,4,4,4). Esses elementos da matriz são então canalizados para os Get-Randomquais extrairão um dos elementos com (pseudo) probabilidade igual. Uma vez que, por exemplo, @(4,1,5)isso nos dá @(4,4,4,4,1,5,5,5,5,5)isso satisfaz os requisitos de probabilidade.


2

C # (.NET Core) , 93 89 87 76 + 18 = 94 bytes

a=>{int i=-1,r=new Random().Next(a.Sum());while(r>=0)r-=a[++i];return a[i];}

Experimente online!

18 bytes extras para using System.Linq;

Reconhecimentos

11 bytes salvos graças a Nevay, cuja implementação de números aleatórios era muito mais concisa (além de ser um em intvez de a double).

Degolfed

a=>{
    int i=-1,
    r=new Random().Next(a.Sum());
    while(r>=0)
        r-=a[++i];
    return a[i];
}

Explicação

Obtenha um número aleatório,, rentre 0 e soma dos elementos. Em cada iteração, subtraia o elemento atual de r. Se rfor menor que 0, retorne esse elemento. A ideia é que existam partes maiores do número aleatório para os números maiores na matriz.


94 bytes:a=>{int i=-1,r=new Random().Next(a.Sum());for(;r>=0;)r-=a[++i];return a[i];}
Nevay 15/09

2

Japonês , 7 bytes

ËÆD
c ö

Teste aqui


Explicação

Entrada implícita da matriz U.

Ë

Mapeie a matriz passando cada elemento através de uma função onde Destá o elemento atual.

ÆD

Gere uma matriz de comprimento De preencha com D.

c

Aplainar.

ö

Obtenha um elemento aleatório.



1

Perl, 31 bytes

@a=map{($_)x$_}@ARGV;$a[rand@a]

Isso pressupõe que a entrada seja argumentos de linha de comando. Observe que pode ficar sem memória se os números forem grandes.




1

Carvão , 12 bytes

F⪪θ;FIι⊞υι‽υ

Experimente online! Link é a versão detalhada do código. Como o Charcoal tenta ser inteligente demais, estou tendo que usar a entrada delimitada por ponto e vírgula para a matriz. Explicação:

  θ             Input variable as string
 ⪪ ;            Split on semicolons
F               Loop i over each string
     Iι         Cast i to integer
    F           Repeat that many times
       ⊞υι      Push i to (originally empty) list
          ‽υ    Random selection from list
                Implicitly print


1

Javascript (ES6), 61 54 bytes

-7 bytes graças a Justin Mariner

a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))

Fragmento de código de exemplo

f=
a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))
console.log(f([4,1,5]))


Você pode somar usando em eval(a.join`+`)vez de reduce.
Justin Mariner

Se você estiver ok com ES7 + você pode usar: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))e chamada cominput::[].find(...)
Downgoat

1

Haskell , 78 77 bytes

import System.Random
f l=randomRIO(0,sum l-1)>>=pure.((l>>= \n->n<$[1..n])!!)

Experimente online! Exemplo de uso: f [1,99]provavelmente produz 99.

Explicação:

  • fpega uma lista de números inteiros le retorna o número inteiro selecionado aleatoriamente como IO Int.
  • l>>= \n->n<$[1..n]constrói uma lista com cada elemento nrepetido nvezes.
  • randomRIO(0,sum l-1) gera um número inteiro no intervalo de 0 ao comprimento da lista de elementos repetidos, que é exatamente a soma de todos os elementos, menos um para evitar uma exceção fora do limite.

Bônus: versão sem pontos de 85 bytes

import System.Random
(>>=).randomRIO.(,)0.pred.sum<*>(pure.).(!!).(>>= \n->n<$[1..n])

Experimente online!



1

Java 8, 127 122 121 bytes

import java.util.*;a->{List l=new Stack();for(int i:a)for(int j=i;j-->0;Collections.shuffle(l))l.add(i);return l.get(0);}

-1 byte graças a @Nevay .

Usa uma abordagem semelhante à resposta Jelly de @ErikTheOutgolfer , adicionando no item nà lista de tempos e, em seguida, selecione um aleatoriamente nessa lista.

Explicação:

Experimente aqui.

import java.util.*;        // Required import for List, Stack and Collections
a->{                       // Method with integer-array parameter and integer return-type
  List l=new Stack();      //  Create a List
  for(int i:a)             //  Loop (1) over the input array
    for(int j=i;j-->0;     //   Inner loop (2) from `i` down to 0
        Collections.shuffle(l))
                           //   and shuffle the List randomly after every iteration
      l.add(i);            //    Add `i` that many times to List `l`
                           //   End of inner loop (2) (implicit / single-line body)
                           //  End of loop (1) (implicit / single-line body)
  return l.get(0);         //  And then return the first item of the list
}                          // End of method

11
Você pode mover a #shufflechamada para o loop for para economizar 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay 15/09

Obrigado @Nevay! Baralhar a lista depois de cada iteração é bastante ineficiente, mas o que nos importa com eficiência, avisos e outras coisas quando podemos nos livrar de mais um byte desagradável? ; p
Kevin Cruijssen


1

GNU APL 1.2, 26 23 bytes; 1,7 21 19 bytes

Abordagem inspirada na resposta de Erik, o Outgolfer's Jelly . Confia em ⎕IOser 0 em vez de 1, que é o padrão para GNU APL (tipo de +5 bytes para⎕IO←0 ).

-3, -2 bytes graças a @ Zacharý

formulário de função

∇f R
S[?⍴S←∊0 0⍉R∘.⍴R]∇

Formulário lambda anônimo

{S[?⍴S←∊0 0⍉⍵∘.⍴⍵]}

Para a explicação, usarei para representar o argumento passado para a função, mas é equivalente a Rno formulário.

⍵∘.⍴⍵calcula o produto externo na lista usando o operador reshape ( ). Efetivamente, isso cria uma tabela (como uma tabela de multiplicação), mas, em vez de multiplicar, repete o elemento na coluna várias vezes igual ao elemento na linha. Para o exemplo dado na pergunta, este é:

4 4 4 4    1 1 1 1    5 5 5 5   
4          1          5         
4 4 4 4 4  1 1 1 1 1  5 5 5 5 5

0 0⍉⍵∘.⍴⍵transpõe a matriz e retorna apenas a diagonal principal. Isso nos fornece apenas as partes em que a linha e a coluna ⍵∘.⍴⍵eram iguais, ou seja, repetimos o número várias vezes igual ao seu valor. Para o exemplo, isto é:

4 4 4 4  1  5 5 5 5 5

transforma seu argumento em uma lista. Usando o operador transpose ( ), obtivemos um vetor contendo 3 vetores. Enlist ( ) o transforma em um único vetor contendo todos os elementos.

S←...atribui esse novo vetor ao vetor S. ⍴Snos dá o comprimento dessa lista. ?é o operador aleatório, portanto, ?⍴Snos fornece um número aleatório entre 0 e o comprimento da lista (exclusivo) (é por isso que ele depende de ⎕IOser 0; caso contrário, está entre 1 e o comprimento, inclusive). S[...]retorna o elemento no índice fornecido.


Você não precisa Q, pois nunca o usa. E no IIRC você pode remover a nova linha antes do del (coisinha triangular que marca o final da função).
Zacharý

Uau, eu nunca sou novo <IO> <IO>⍉em obter a diagonal principal foi uma coisa!
Zacharý 15/09/17

@ Zacharý Certo, obrigado. Francamente, eu nem sabia sobre a coisa da transposição até que tentei essa tarefa. Encontrado aqui
Arc676 16/17

Ah, existe um APL gratuito muito melhor que o GNU, é chamado ngn APL. É realmente muito legal! ( Ngn.github.io/apl/web , mas ele não tem tradfn)
Zachary

@ Zacharý Eu também tenho esse :) infelizmente a função de transposição não funciona (ou eu perdi alguma coisa). Vou testá-lo novamente agora que compreendo melhor como ele funciona.
precisa saber é o seguinte

1

MATLAB, 30 bytes

@(a)datasample(repelem(n,n),1)

Isso pressupõe o MATLAB R2015a ou mais recente e com a caixa de ferramentas Estatísticas e aprendizado de máquina instalada.

Veja a explicação abaixo para saber como repelemé usado. A diferença entre este menor e o abaixo é que a caixa de ferramentas S&ML inclui a função datasampleque pode ser usada para obter um ou mais elementos de uma matriz aleatoriamente (com probabilidade uniforme), o que permite que uma função anônima seja usada, eliminando oinput/disp chamadas.

MATLAB, 49 bytes

n=input('');a=repelem(n,n);disp(a(randi(nnz(a))))

Este código pressupõe que o MATLAB R2015a ou mais recente seja usado como quando a repelemfunção foi introduzida. repelemé uma função que aceita dois parâmetros, o primeiro é uma matriz de números a serem replicados e a segunda é uma matriz de quantas vezes o elemento correspondente deve ser replicado. Essencialmente, a função executa decodificação de duração, fornecendo o número e a duração.

Ao fornecer a mesma entrada para ambas as entradas repelem, terminamos com uma matriz que consiste em n vezes mais do elemento n, se isso faz sentido. Se você forneceu [1 2 3], receberia [1 2 2 3 3 3]. Se você forneceu [1 2 4 2], receberia [1 2 2 4 4 4 4 2 2]. Ao fazer isso, significa que, se selecionarmos um elemento com probabilidade uniforme ( randi(m)fornecer um número inteiro aleatório de 1 a m com probabilidade uniforme), cada elemento n terá uma probabilidade n vezes maior de ser selecionado. No primeiro exemplo de [1 2 3], 1teria uma chance de 1/6, 2teria uma chance de 2/6 e 3teria uma chance de 3/6.


Como uma observação lateral, como repelemainda não está disponível para o Octave, não posso fornecer um link TIO. Além disso, porque Octave não pode ser utilizado há uma penalidade de caráter grande quanto input()e disp()necessidade de ser usado como uma função anônima não é possível. Se o Octave suportasse repelem, o seguinte poderia ser usado:

@(n)a(randi(nnz(a=repelem(n,n))))

Isso teria economizado 16 bytes, mas não era para ser.


Realmente aprecio a explicação, obrigado!
Ian H.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.