Seleziona in modo casuale da un array


19

Questa sfida è piuttosto semplice:
ti viene data una matrice di numeri interi positivi (escluso 0) e devi selezionare un elemento casuale da questa matrice.

Ma ecco il colpo di scena:
la probabilità di selezionare un elemento dipende dal valore dell'intero, il che significa che l'intero diventa più grande, anche la probabilità che venga selezionato!

Esempio

Ti viene dato l'array [4, 1, 5].

La probabilità di selezionare 4 è uguale a 4 divisa per la somma di tutti gli elementi dell'array , in questo caso 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
La probabilità di selezionare 1 è 1 / 10o 10%.

Ingresso

Una matrice di numeri interi positivi.

Produzione

Restituisce il numero intero selezionato se si utilizza un metodo o stamparlo direttamente su stdout.

Regole

  • Questo è quindi vince il codice più breve in byte in qualsiasi lingua.
  • Sono vietate le scappatoie standard.

Risposte:


20

Gelatina , 3 byte

x`X

Provalo online!

Guarda, no, nessun Unicode!

Spiegazione:

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

1
Puoi spiegare cosa fa il tuo codice, per favore? :)
Ian H.

1
@IanH. È davvero un semplice algoritmo ripetere ogni elemento stesso volte quindi scegliere a caso.
Erik the Outgolfer,

16

R , 25 byte

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

Provalo online!

Spiegazione:

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

Prende un campione dalle sdimensioni 1senza sostituzione, con pesi s; questi sono riscalati per essere probabilità.

Per verificare la distribuzione, utilizzare questo collegamento .


mi hai battuto per 9 mesi! : D
JayCe

@JayCe heh, il mio unico vantaggio su di te sembra essere "andare per primo" dato che sei piuttosto il golfista! :-)
Giuseppe,

13

Pyth , 4 byte

OsmR

Provalo qui.

Salvato un byte, grazie a @Jakube, con un approccio piuttosto insolito.

Pyth , 5 byte

Osm*]

Provalo qui!

Come?

1 #

OsmR - Programma completo.

   R - Mappa destra ...
  m - ... Uso della mappa. Ciò crea essenzialmente l'elenco [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Il merito va a Jakube per questo!
 s - Appiattisci.
O - Elemento casuale di ^. Visualizza implicitamente.

2 #

Osm *] - Programma completo.

  m - Mappa sopra l'ingresso.
    ] - L'elemento corrente, d, avvolto; [D].
   * - Ripetute volte.
 s - Appiattisci.
O - Elemento casuale. Stampa implicitamente il risultato.

1
Posso farlo in 4. Devo rovinarlo o vuoi trovarlo da solo?
Jakube,

2
@Jakube Aspetta un po '. Voglio vedere se riesco a farlo. E ' che ovvio?
Mr. Xcoder,

1
@Jakube Ok, eseguirò il ping quando mi arrendo.
Mr. Xcoder,

1
OsmLoppureOsmR
Jakube,

1
@Jakube Ooh che è molto intelligente! Argomento implicito d, quindi mappa dsu un intervallo ... genio!
Erik the Outgolfer,

8

CJam (9 byte)

q~_]ze~mR

Demo online . Questo è un programma completo che accetta input in formato array CJam su stdin e stampa l'elemento selezionato su stdout.

Dissezione

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

1
Un golf così potente per un compito così semplice.
Erik the Outgolfer,

7

Perl 6 , 20 byte

Salvato 1 byte grazie a @Brad Gilbert b2gills.

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

Provalo online!

Questo richiede 1 argomento dell'elenco. Comprimiamo 2 copie di questo elenco utilizzando l' xxoperatore. Quindi @_ Zxx@_, otteniamo un elenco in cui l'elemento xviene presentato xvolte. Viene quindi forzato a Bag, che è una raccolta che memorizza oggetti insieme a quante volte compaiono nella raccolta. Infine, scegliamo un elemento casuale da questa raccolta con pick, che prende i conti nell'account e fa The Right Thing ™.


Questo può essere abbreviato in{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills

@ BradGilbertb2gills, purtroppo non funziona. Crea una borsa dalle coppie (quindi non ci sarebbe "1" una volta, "2" due volte ecc., Ma "1 => 1" una volta, "2 => 2" anche una volta ecc. - Non quello che voglio) . Questo perché i compositori non sono costruttori, come spiegato in questo Calendario dell'Avvento .
Ramillies,

@ BradGilbertb2gills, ma grazie comunque, mi hai aiutato a giocare a golf in alcuni spazi qui e anche in altre sfide!
Ramillies,

Intendevo{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills il

Aah, capisco. Perché non mi è venuto in mente ...: -) Grazie.
Ramillies,


5

MATL , 8 6 byte

tY"1Zr

Provalo su MATL Online!

Spiegazione

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 byte

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

Provalo online!


Potresti aggiungere una spiegazione? Sto cercando di capire perché for(r*=Math.random();;)è necessario o se tutto ciò che serve è r*=Math.random().
Ayb4btu,

@ Ayb4btu Senza il for(;;)ciclo ciò richiederebbe una seconda istruzione di ritorno (mai raggiunta) dopo il for(int i:a)...per soddisfare il compilatore - che sarebbe più lungo di 3 byte.
Nevay,

Ah, certo, il tuo for(int i:a)è come un foreachC #. Ho avuto lo stesso problema, ma ho appena usato un forloop continuo. La tua nuova risposta mi incuriosisce, potrei provare a rubare alcune delle tue idee.
Ayb4btu,

3

J, 8 7 8 byte

Il 7 byte non è valido; Tornerò a una modifica precedente quando torno al mio computer tra un giorno o due.

Provalo online!

?@+/{#~

:( la selezione di elementi casuali da un array è costosa.

8 byte

#~{~1?+/

9 byte

(1?+/){#~

Spiegazione

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

?@+/è (?@+)/; Temo che dovresti sbatterlo di nuovo fino a 8 ...
FireFly,

@FireFly avrei dovuto testarlo di più, buona cattura.
Cole

3

JavaScript (ES6), 50 byte

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

Spero sia evidente come funzioni, ma lo spiegherò qui comunque. Ordina gli interi in ordine decrescente, quindi ne sceglie uno a caso con una distrubuzione beta (1 / 2,1) .


Non penso che questo avrà la distribuzione corretta. I miei test mostrano che con a=[4,1,5], otterrai circa il 18% 1, il 24% 4e il 58% 5, il che suggerisce che otterrai quella distribuzione con qualsiasi input di lunghezza 3.
Giuseppe,

Mi sembra corretto. Numero intero più alto, probabilità più alta.
kamoroso94,

Oh, capisco. Ho letto male la domanda. Ottima soluzione, +1!
Giuseppe,


2

PowerShell , 27 byte

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

Provalo online!

Accetta input $args[0]come un array letterale. Passa attraverso ciascun elemento |%{...}e ogni iterazione costruisce una nuova matrice ,$_di $_elementi - ad esempio, per 4questo creerà una matrice @(4,4,4,4). Questi elementi dell'array vengono quindi convogliati in Get-Randomcui verrà estratto uno degli elementi con (pseudo) probabilità uguale. Dal momento che, ad esempio, per @(4,1,5)questo ci dà @(4,4,4,4,1,5,5,5,5,5)questo soddisfa i requisiti di probabilità.


2

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

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

Provalo online!

Ulteriori 18 byte per using System.Linq;

Ringraziamenti

11 byte salvati grazie a Nevay, la cui implementazione di numeri casuali è stata molto più concisa (oltre a essere intinvece di a double).

Degolfed

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

Spiegazione

Ottieni un numero casuale r, tra 0 e la somma degli elementi. Quindi ad ogni iterazione sottrai l'elemento corrente da r. Se rè inferiore a 0, restituisce questo elemento. L'idea è che ci sono parti più grandi del numero casuale per i numeri più grandi nella matrice.


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

2

Japt , 7 byte

ËÆD
c ö

Provalo qui


Spiegazione

Input implicito di array U.

Ë

Mappa sull'array passando ciascun elemento attraverso una funzione in cui si Dtrova l'elemento corrente.

ÆD

Genera una matrice di lunghezza De riempila D.

c

Appiattire.

ö

Ottieni un elemento casuale.



1

Perl, 31 byte

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

Ciò presuppone che l'input sia argomenti della riga di comando. Si noti che potrebbe esaurire la memoria se i numeri sono grandi.




1

Carbone , 12 byte

F⪪θ;FIι⊞υι‽υ

Provalo online! Il collegamento è alla versione dettagliata del codice. Poiché Charcoal cerca di essere troppo intelligente, devo usare l'input delimitato da punti e virgola per l'array. Spiegazione:

  θ             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 byte

-7 byte grazie a @Justin Mariner

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

Esempio di frammento di codice

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


Puoi sommare usando eval(a.join`+`)invece di reduce.
Justin Mariner,

Se stai bene con ES7 + puoi usare: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))e chiamare coninput::[].find(...)
Downgoat

1

Haskell , 78 77 byte

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

Provalo online! Esempio di utilizzo:f [1,99] probabilmente rese 99.

Spiegazione:

  • fprende un elenco di numeri interi le restituisce il numero intero selezionato casualmente comeIO Int .
  • l>>= \n->n<$[1..n]costruisce un elenco con ogni elemento nripetuton volte.
  • randomRIO(0,sum l-1) restituisce un numero intero nell'intervallo compreso tra 0 e la lunghezza dell'elenco di elementi ripetuti, che è esattamente la somma di tutti gli elementi, meno uno per evitare un'eccezione fuori limite.

Bonus: versione senza punti a 85 byte

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

Provalo online!



1

Java 8, 127 122 121 byte

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 grazie a @Nevay .

Utilizza un approccio simile alla risposta Jelly di @ErikTheOutgolfer , aggiungendo nvolte l'elemento nalla lista, quindi selezionandone uno a caso da quella lista.

Spiegazione:

Provalo qui.

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

1
È possibile spostare la #shufflechiamata nel ciclo for per salvare 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay,

@Nevay Grazie! Mescolare l'elenco dopo ogni iterazione è piuttosto inefficiente, ma cosa ci interessa dell'efficienza, degli avvisi e simili quando possiamo liberarci di un fastidioso byte aggiuntivo. ; p
Kevin Cruijssen,

1

Dyalog APL , 8 byte

/⍨⌷⍨1?+/

Provalo online!

Come?

  • /⍨, ncopie di nper ciascunon per l'argomento.
  • ⌷⍨, all'indice di
  • 1?, un valore casuale tra 1 e
  • +/, la somma dell'argomento

1

GNU APL 1.2, 26 23 byte; 1.7 21 19 byte

Approccio ispirato alla risposta Jelly di Erik the Outgolfer . Si basa ⎕IOsull'essere 0 anziché 1, che è l'impostazione predefinita per GNU APL (ordinamento di +5 byte per⎕IO←0 ).

-3, -2 byte grazie a @ Zacharý

modulo di funzione

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

Forma lambda anonima

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

Per la spiegazione, userò per rappresentare l'argomento passato alla funzione, ma è equivalente a Rnel modulo.

⍵∘.⍴⍵calcola il prodotto esterno nell'elenco usando l' operatore reshape ( ). In effetti, questo crea una tabella (come una tabella di moltiplicazione) ma invece di moltiplicarsi, ripete l'elemento nella colonna un numero di volte uguale all'elemento nella riga. Per l'esempio fornito nella domanda, questo è:

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⍉⍵∘.⍴⍵traspone la matrice e restituisce solo la diagonale principale. Questo ci dà solo le parti in cui la riga e la colonna ⍵∘.⍴⍵erano uguali, cioè abbiamo ripetuto il numero un numero di volte uguale al suo valore. Per l'esempio, questo è:

4 4 4 4  1  5 5 5 5 5

trasforma il suo argomento in un elenco. Usando l' operatore transpose ( ), abbiamo ottenuto un vettore contenente 3 vettori. Enlist ( ) lo trasforma in un singolo vettore contenente tutti gli elementi.

S←...assegna questo nuovo vettore al vettore S. ⍴Sci fornisce la lunghezza di tale elenco. ?è l'operatore casuale, quindi ?⍴Sci dà un numero casuale compreso tra 0 e la lunghezza dell'elenco (esclusivo) (per questo si basa ⎕IOsull'essere 0; altrimenti è compreso tra 1 e la lunghezza, incluso). S[...]restituisce l'elemento in corrispondenza dell'indice indicato.


Non hai bisogno Q, dal momento che non lo usi mai. E IIRC puoi rimuovere la nuova riga prima del del (piccola cosa triangolare che segna la fine della funzione.)
Zacharý

Caspita, non sono mai stato nuovo <IO> <IO>⍉per ottenere la diagonale principale!
Zacharý,

@ Zacharý Giusto, grazie. Francamente, non sapevo nemmeno della cosa da trasporre fino a quando non ho provato questo compito. L'ho trovato qui
Arc676,

Oh, esiste un APL gratuito molto migliore di GNU, si chiama ngn APL. In realtà è piuttosto bello! ( ngn.github.io/apl/web , ma non ha tradfn)
Zacharý

@ Zacharý Ne ho uno anch'io :) purtroppo la funzione di trasposizione non funziona (o ho perso qualcosa). Lo testerò di nuovo ora che ho una migliore comprensione di come funziona.
Arc676

1

MATLAB, 30 byte

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

Ciò presuppone MATLAB R2015a o più recente e con la casella degli strumenti Statistica e apprendimento automatico installata.

Vedere la spiegazione di seguito per come repelemviene utilizzato. La differenza tra questo più breve e quello sotto è che la toolbox S&ML include la funzione datasampleche può essere usata per prendere uno o più elementi da un array a caso (con probabilità uniforme) che consente di usare una funzione anonima, togliendo input/dispchiamate.

MATLAB, 49 byte

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

Questo codice presuppone che sia utilizzato MATLAB R2015a o più recente quando è repelemstata introdotta la funzione. repelemè una funzione che accetta due parametri, il primo è un array di numeri da replicare e il secondo è un array di quante volte deve essere replicato l'elemento corrispondente. In sostanza, la funzione esegue la decodifica della lunghezza fornendo il numero e la lunghezza della corsa.

Fornendo lo stesso input ad entrambi gli input di repelemnoi finiamo con un array che consiste di n volte di più dell'elemento n se questo ha senso. Se lo avessi fornito [1 2 3]lo avresti ottenuto [1 2 2 3 3 3]. Se lo avessi fornito [1 2 4 2]lo avresti ottenuto [1 2 2 4 4 4 4 2 2]. In questo modo significa che se selezioniamo un elemento con probabilità uniforme ( randi(m)da un intero casuale da 1 a m con probabilità uniforme), ogni elemento n ha una probabilità n volte maggiore di essere selezionato. Nel primo esempio di [1 2 3], 1avrebbe una probabilità 1/6, 2avrebbe una probabilità 2/6 e 3avrebbe una probabilità 3/6.


Come nota a margine, poiché repelemnon è ancora disponibile per Octave, non posso fornire un collegamento TIO. Inoltre, perché Octave non può essere utilizzato è prevista una penale grande carattere input()e disp()necessità di essere usato come una funzione anonima non è possibile. Se Octave è supportatorepelem , è possibile utilizzare quanto segue:

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

Ciò avrebbe salvato 16 byte, ma non lo era.


Apprezzo molto la spiegazione, grazie!
Ian H.,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.