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.

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

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 .


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.

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

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 ™.


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


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




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!


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

?@+/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) .


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.


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.


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.



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.




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


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]))


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!



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

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

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.


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.


Really appreciate the explanation, thanks!
Ian H.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.