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.
Ian H.
fonte

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
Erik, o Outgolfer
fonte
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 .

Giuseppe
fonte
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.
Mr. Xcoder
fonte
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
Peter Taylor
fonte
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 ™.

Ramillies
fonte
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
6

Python 3.6 , 44 bytes

lambda A:choices(A,A)[0]
from random import*

Yay para embutidos. O outro Aem choices(A, A)é um weightsargumento opcional .

Experimente online!

shooqie
fonte
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
Luis Mendo
fonte
5

Mathematica, 19 bytes

RandomChoice[#->#]&
J42161217
fonte
4

Python 3 , 62 bytes

lambda k:choice(sum([x*[x]for x in k],[]))
from random import*

Experimente online!

Mr. Xcoder
fonte
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!

Nevay
fonte
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
Cole
fonte
?@+/é (?@+)/; 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) .

kamoroso94
fonte
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.

AdmBorkBork
fonte
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.

Ayb4btu
fonte
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.

Shaggy
fonte
2

CJam , 5 bytes

lS/mR

Experimente online! Nota: números separados por um espaço

lolad
fonte
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.


fonte
1

Perl 5 , 31 + 1 (-a) = 32 bytes

@p=map{($_)x$_}@F;say$p[rand@p]

Experimente online!

Xcali
fonte
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
Neil
fonte
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]))

Herman L
fonte
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!

Laikoni
fonte
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
Kevin Cruijssen
fonte
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

Dyalog APL , 8 bytes

/⍨⌷⍨1?+/

Experimente online!

Quão?

  • /⍨, ncópias de npara cada um nno argumento.
  • ⌷⍨, no índice de
  • 1?, um valor aleatório entre 1e
  • +/, a soma do argumento
Zacharý
fonte
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.

Arc676
fonte
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.

Tom Carpenter
fonte
Realmente aprecio a explicação, obrigado!
Ian H.