Losowo wybierz z tablicy

19

To wyzwanie jest raczej proste:
otrzymujesz tablicę dodatnich (nie licząc 0) liczb całkowitych i musisz wybrać losowy element z tej tablicy.

Ale oto zwrot akcji:
prawdopodobieństwo wyboru elementu zależy od wartości liczby całkowitej, co oznacza, że ​​wraz ze wzrostem liczby całkowitej rośnie również prawdopodobieństwo jej wyboru!

Przykład

Dostajesz tablicę [4, 1, 5].

Prawdopodobieństwo wybrania 4 jest równe 4 podzielone przez sumę wszystkich elementów w tablicy , w tym przypadku 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
Prawdopodobieństwo wyboru 1 to 1 / 10lub 10%.

Wejście

Tablica dodatnich liczb całkowitych.

Wynik

Zwróć wybraną liczbę całkowitą, jeśli używasz metody, lub wydrukuj ją bezpośrednio stdout.

Zasady

  • To jest więc wygrywa najkrótszy kod w bajtach w dowolnym języku.
  • Standardowe luki są zabronione.
Ian H.
źródło

Odpowiedzi:

20

Galaretka , 3 bajty

x`X

Wypróbuj online!

Spójrz, nie ma Unicode!

Wyjaśnienie:

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 the Outgolfer
źródło
1
Czy możesz wyjaśnić, co robi Twój kod? :)
Ian H.,
1
@IanH. To naprawdę prosty algorytm, powtarzaj każdy element osobno razy, a następnie wybierz losowo.
Erik the Outgolfer
16

R , 25 bajtów

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

Wypróbuj online!

Wyjaśnienie:

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

Pobiera próbkę swielkości 1bez wymiany, z odważnikami s; są one przeskalowane do prawdopodobieństw.

Aby zweryfikować dystrybucję, użyj tego linku .

Giuseppe
źródło
pobiłeś mnie do tego przez 9 miesięcy! : D
JayCe,
@JayCe heh, moją jedyną przewagą nad tobą wydaje się być „pierwszy”, ponieważ jesteś całkiem golfistą! :-)
Giuseppe,
13

Pyth , 4 bajty

OsmR

Wypróbuj tutaj.

Oszczędność jednego bajtu dzięki @Jakube, z dość nietypowym podejściem.

Pyth , 5 bajtów

Osm*]

Wypróbuj tutaj!

W jaki sposób?

# 1

OsmR - Pełny program.

   R - Prawa mapa ...
  m - ... Korzystanie z mapy. To zasadniczo tworzy listę [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Podziękowania dla Jakube za to!
 s - Spłaszcz.
O - Losowy element ^. Wyświetlaj niejawnie.

# 2

Osm *] - Pełny program.

  m - Mapa nad wejściem.
    ] - Bieżący element, d, zawinięty; [re].
   * - Powtarzane d razy.
 s - Spłaszcz.
O - losowy element. Wydrukuj wynik niejawnie.
Pan Xcoder
źródło
1
Mogę to zrobić w 4. Czy powinienem to zepsuć, czy chcesz to znaleźć sam?
Jakube
2
@Jakube Poczekaj chwilę. Chcę zobaczyć, czy dam radę. Czy jest to oczywiste?
Pan Xcoder,
1
@Jakube Ok, pinguję, kiedy się poddaję.
Pan Xcoder,
1
OsmLlubOsmR
Jakube
1
@Jakube Ooh, to jest bardzo sprytne! Argument niejawny d, a następnie mapy dw zakresie ... geniusz!
Erik the Outgolfer,
8

CJam (9 bajtów)

q~_]ze~mR

Demo online . Jest to pełny program, który pobiera dane wejściowe w formacie tablicy CJam na standardowe wejście i drukuje wybrany element na standardowe wyjście.

Sekcja

q~   e# Read and parse input
_]z  e# Copy and transpose
e~   e# Run-length decode
mR   e# Select random element uniformly
Peter Taylor
źródło
1
Potężny golf do tak prostych zadań.
Erik the Outgolfer
7

Perl 6 , 20 bajtów

Oszczędność 1 bajtu dzięki @Brad Gilbert b2gills.

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

Wypróbuj online!

To wymaga 1 argumentu listy. Spakowujemy 2 kopie tej listy za pomocą xxoperatora. Tak więc @_ Zxx@_, otrzymujemy listę, w której element xjest prezentowany xrazy. Następnie jest przymuszany do Bag, która jest kolekcją, która przechowuje obiekty wraz z tym, ile razy pojawiają się w kolekcji. Na koniec wybieramy losowy element z tej kolekcji pick, który bierze pod uwagę liczby i robi The Right Thing ™.

Ramillies
źródło
Można to skrócić do{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills
@ BradGilbertb2gills, niestety to nie działa. Tworzy torbę z par (więc nie byłoby „1” raz, „2” dwa razy itd., Ale „1 => 1” raz, „2 => 2” także raz itd. - nie to, czego chcę) . To dlatego, że kompozytorzy nie są przymusami, jak wyjaśniono w tym kalendarzu adwentowym .
Ramillies,
@ BradGilbertb2gills, ale i tak dziękuję, pomogłeś mi zagrać w golfa tutaj i w innych wyzwaniach!
Ramillies,
Miałem na myśli{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills
Rozumiem. Dlaczego mi się nie przyszło ...: -) Dzięki.
Ramillies
6

Python 3.6 , 44 bajty

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

Yay dla wbudowanych. Drugi Aw choices(A, A)to opcjonalny weightsargument.

Wypróbuj online!

shooqie
źródło
5

MATL , 8 6 bajtów

tY"1Zr

Wypróbuj w MATL Online!

Wyjaśnienie

t    % Implicit input. Duplicate
Y"   % Run-length decoding
1Zr  % Randomly take one value with uniform distribution. Implicitly display
Luis Mendo
źródło
5

Mathematica, 19 bajtów

RandomChoice[#->#]&
J42161217
źródło
4

Python 3 , 62 bajty

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

Wypróbuj online!

Pan Xcoder
źródło
4

Java (OpenJDK 8) , 88 87 86 83 bajtów

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

Wypróbuj online!

Nieważne
źródło
Czy możesz dodać wyjaśnienie? Próbuję zrozumieć, dlaczego for(r*=Math.random();;)jest to potrzebne lub czy wszystko, czego potrzebujesz, to r*=Math.random().
Ayb4btu
@ Ayb4btu Bez for(;;)pętli wymagałoby to drugiej (nigdy nie osiągniętej) instrukcji return po for(int i:a)...spełnieniu wymagań kompilatora - która byłaby o 3 bajty dłuższa.
Nevay
Ach, oczywiście, twój for(int i:a)jest jak foreachw C #. Miałem ten sam problem, ale po prostu użyłem forpętli. Twoja nowa odpowiedź intryguje mnie, mogę spróbować przekreślić niektóre z twoich pomysłów.
Ayb4btu
3

J, 8 7 8 bajtów

7 bajtów jest nieprawidłowy; Przywrócę to do poprzedniej edycji, gdy wrócę do komputera za dzień lub dwa.

Wypróbuj online!

?@+/{#~

:( wybranie losowych elementów z tablicy jest kosztowne.

8 bajtów

#~{~1?+/

9 bajtów

(1?+/){#~

Wyjaśnienie

?@+/{#~
?        Choose random number in range
  +/     Sum of the array
    {    Select that element from
     #~  The elements duplicated as many times as their value
kapusta
źródło
?@+/jest (?@+)/; Obawiam się, że będziesz musiał ponownie podnieść to do 8…
FireFly
@FireFly Powinienem był to przetestować, dobry połów.
cole
3

JavaScript (ES6), 50 bajtów

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

Mam nadzieję, że to oczywiste, jak to działa, ale i tak to wyjaśnię. Sortuje liczby całkowite w kolejności malejącej, a następnie wybiera jedną losowo z rozproszeniem beta (1 / 2,1) .

kamoroso94
źródło
Nie sądzę, żeby miało to prawidłową dystrybucję. Moje testy pokazują, że z a=[4,1,5], otrzymasz około 18% 1, 24% 4i 58% 5, co sugeruje, że otrzymasz ten rozkład z dowolnym wkładem o długości 3.
Giuseppe,
To wydaje mi się poprawne. Wyższa liczba całkowita, większe prawdopodobieństwo.
kamoroso94,
Rozumiem. Źle odczytałem pytanie. Doskonałe rozwiązanie, +1!
Giuseppe,
2

PowerShell , 27 bajtów

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

Wypróbuj online!

Pobiera dane wejściowe $args[0] jako tablicę literalną. Pętle przez każdy element |%{...}, a w każdej iteracji tworzy się nową tablicę ,$_z $_pierwiastków - na przykład dla 4tego utworzy tablicę @(4,4,4,4). Te elementy tablicy są następnie wpompowywane w rurę, z Get-Randomktórej wydobywa się jeden z elementów z (pseudo) równym prawdopodobieństwem. Ponieważ np. @(4,1,5)Daje nam @(4,4,4,4,1,5,5,5,5,5)to spełnienie wymagań prawdopodobieństwa.

AdmBorkBork
źródło
2

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

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

Wypróbuj online!

Dodatkowe 18 bajtów dla using System.Linq;

Podziękowanie

11 bajtów zaoszczędzonych dzięki Nevayowi, którego implementacja liczb losowych była o wiele bardziej zwięzła (a także być int zamiast adouble ).

Degolfed

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

Wyjaśnienie

Uzyskaj losową liczbę rod 0 do sumy elementów. Następnie przy każdej iteracji odejmij bieżący element r. Jeśli rjest mniejsze niż 0, zwróć ten element. Chodzi o to, że są większe części liczby losowej dla większych liczb w tablicy.

Ayb4btu
źródło
94 bajty:a=>{int i=-1,r=new Random().Next(a.Sum());for(;r>=0;)r-=a[++i];return a[i];}
Nevay
2

Japt , 7 bajtów

ËÆD
c ö

Sprawdź to tutaj


Wyjaśnienie

Domniemane wejście tablicy U.

Ë

Odwzoruj tablicę, przepuszczając każdy element przez funkcję, gdzie Djest bieżący element.

ÆD

Wygeneruj tablicę długości Di wypełnij ją D.

c

Spłaszczyć.

ö

Zdobądź losowy element.

Kudłaty
źródło
1

Perl, 31 bajtów

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

Zakłada się, że dane wejściowe są argumentami wiersza poleceń. Pamiętaj, że może zabraknąć pamięci, jeśli liczby są duże.


źródło
1

Węgiel drzewny , 12 bajtów

F⪪θ;FIι⊞υι‽υ

Wypróbuj online! Link jest do pełnej wersji kodu. Ponieważ Charcoal próbuje być zbyt sprytny, muszę użyć danych rozdzielanych średnikami dla tablicy. Wyjaśnienie:

  θ             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
źródło
1

JavaScript (ES6), 61 54 bajtów

-7 bajtów dzięki @Justin Mariner

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

Przykładowy fragment kodu

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

Herman L.
źródło
Możesz zsumować za pomocą eval(a.join`+`)zamiast reduce.
Justin Mariner
Jeśli nie masz [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join))input::[].find(...)
nic przeciwko ES7
1

Haskell , 78 77 bajtów

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

Wypróbuj online! Przykład użycia: f [1,99]prawdopodobnie daje 99.

Wyjaśnienie:

  • f pobiera listę liczb całkowitych l i zwraca losowo wybraną liczbę całkowitą jakoIO Int .
  • l>>= \n->n<$[1..n]konstruuje listę z każdym npowtórzonym elementemn razy.
  • randomRIO(0,sum l-1) zwraca liczbę całkowitą z zakresu od 0 do długości listy powtarzanych elementów, która jest dokładnie sumą wszystkich elementów, minus jeden, aby uniknąć wyjątku spoza zakresu.

Bonus: 85-bajtowa wersja bez punktów

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

Wypróbuj online!

Laikoni
źródło
1

Java 8, 127 122 121 bajtów

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 bajt dzięki @Nevay .

Stosuje podobne podejście, jak odpowiedź Jelly @ErikTheOutgolfer , dodając nrazy pozycję ndo listy, a następnie wybierz jedną losowo z tej listy.

Wyjaśnienie:

Wypróbuj tutaj.

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
źródło
1
Możesz przenieść #shufflepołączenie do pętli for, aby zaoszczędzić 1 bajt for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay
@Nevay Thanks! Przetasowanie listy po każdej iteracji jest dość nieefektywne, ale na czym nam zależy wydajność, ostrzeżenia i takie, kiedy możemy pozbyć się jednego dodatkowego nieznośnego bajtu. ; p
Kevin Cruijssen
1

Dyalog APL , 8 bajtów

/⍨⌷⍨1?+/

Wypróbuj online!

W jaki sposób?

  • /⍨, nkopie nkażdego nw argumencie.
  • ⌷⍨, według indeksu
  • 1?, losowa wartość pomiędzy 1i
  • +/, suma argumentu
Zacharý
źródło
1

GNU APL 1.2, 26 23 bajtów; 1.7 21 19 bajtów

Podejście zainspirowane odpowiedzią Erika the Outgolfer's Jelly . Polega na ⎕IObyciu 0 zamiast 1, co jest wartością domyślną dla GNU APL (rodzaj +5 bajtów dla ⎕IO←0).

-3, -2 bajty dzięki @ Zacharý

formularz funkcyjny

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

Anonimowa forma lambda

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

Dla wyjaśnienia użyję do przedstawienia argumentu przekazanego do funkcji, ale jest ona równoważna Rz formą.

⍵∘.⍴⍵oblicza zewnętrzny produkt z listy za pomocą operatora reshape ( ). W efekcie tworzy to tabelę (jak tabliczka mnożenia), ale zamiast mnożenia powtarza element w kolumnie kilka razy równy elementowi w wierszu. Dla przykładu podanego w pytaniu jest to:

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⍉⍵∘.⍴⍵transponuje macierz i zwraca tylko główną przekątną. To daje nam tylko te części, w których wiersz i kolumna ⍵∘.⍴⍵były takie same, tzn. Powtórzyliśmy liczbę kilka razy równą jej wartości. Na przykład jest to:

4 4 4 4  1  5 5 5 5 5

zamienia argument w listę. Za pomocą operatora transpose ( ) otrzymaliśmy wektor zawierający 3 wektory. Enlist ( ) zamienia go w pojedynczy wektor zawierający wszystkie elementy.

S←...przypisuje ten nowy wektor do wektora S. ⍴Sdaje nam długość tej listy. ?jest operatorem losowym, więc ?⍴Sdaje nam losową liczbę od 0 do długości listy (wyłączne) (dlatego opiera się na ⎕IObyciu 0; w przeciwnym razie jest między 1 a długością włącznie). S[...]zwraca element o podanym indeksie.

Arc676
źródło
Nie potrzebujesz Q, bo nigdy go nie używasz. I IIRC możesz usunąć znak nowej linii przed del (mała rzecz trójkątna oznaczająca koniec funkcji.)
Zacharý
Wow, I never new <IO> <IO>⍉ to get the main diagonal was even a thing!
Zacharý
@Zacharý Right, thanks. Frankly, I didn't even know about the transpose thing until I tried this task either. Found it here
Arc676
Oh, there does exist a much better free APL than GNU, it's called ngn APL. It's actually pretty cool! (ngn.github.io/apl/web, but it doesn't have tradfn)
Zacharý
@Zacharý I have that one too :) unfortunately the transpose function doesn't work (or I missed something). I will be testing it again now that I have a better understanding of how it works.
Arc676
1

MATLAB, 30 bytes

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

This assumes MATLAB R2015a or newer and with the Statistics & Machine Learning toolbox installed.

See the explanation below for how repelem is used. The difference between this shorter one and the one below is that the S&ML toolbox includes the function datasample which can be used to take one or more elements from an array at random (with uniform probability) which allows an anonymous function to be used, stripping away the input/disp calls.

MATLAB, 49 bytes

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

This code assumes that MATLAB R2015a or newer is used as that is when the repelem function was introduced. repelem is a function which takes two parameters, the first is an array of numbers to be replicated, and the second is an array of how many times the corresponding element should be replicated. Essentially the function performs run-length decoding by providing the number and the run-length.

By providing the same input to both inputs of repelem we end up with an array which consists of n times more of element n if that makes sense. If you provided [1 2 3] you would get [1 2 2 3 3 3]. If you provided [1 2 4 2] you would get [1 2 2 4 4 4 4 2 2]. By doing this it means that if we select an element with uniform probability (randi(m) gives a random integer from 1 to m with uniform probability), each element n has an n times higher probability of being selected. In the first example of [1 2 3], 1 would have a 1/6 chance, 2 would have a 2/6 chance and 3 would have a 3/6 chance.


As a side note, because repelem is not available yet for Octave, I can't give a TIO link. Additionally because Octave can't be used there is a big character penalty as input() and disp() need to be used as an anonymous function is not possible. If Octave supported repelem, the following could be used:

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

That would have saved 16 bytes, but it was not to be.

Tom Carpenter
źródło
Really appreciate the explanation, thanks!
Ian H.