Zufällig aus einem Array auswählen


19

Diese Herausforderung ist recht einfach:
Sie erhalten ein Array positiver (ohne 0) Ganzzahlen und müssen ein zufälliges Element aus diesem Array auswählen.

Aber hier ist die Wendung:
Die Wahrscheinlichkeit, ein Element auszuwählen, hängt vom Wert der Ganzzahl ab, dh je größer die Ganzzahl wird, desto größer ist auch die Wahrscheinlichkeit, dass es ausgewählt wird!

Beispiel

Sie erhalten das Array [4, 1, 5].

In diesem Fall ist die Wahrscheinlichkeit der Auswahl von 4 gleich 4 geteilt durch die Summe aller Elemente im Array4 / ( 4 + 1 + 5 ) = 4 / 10 =40% .
Die Wahrscheinlichkeit für die Auswahl von 1 ist 1 / 10oder 10%.

Eingang

Eine Reihe von positiven ganzen Zahlen.

Ausgabe

Gibt die ausgewählte Ganzzahl zurück, wenn eine Methode verwendet wird, oder druckt sie direkt aus stdout.

Regeln

  • Dies ist so dass der kürzeste Code in Bytes in jeder Sprache gewinnt.
  • Standardlücken sind verboten.

Antworten:


20

Gelee , 3 Bytes

x`X

Probieren Sie es online!

Schau ma, kein Unicode!

Erläuterung:

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
Können Sie bitte erklären, was Ihr Code macht? :)
Ian H.

1
@IanH. Es ist wirklich ein einfacher Algorithmus, der jedes Element selbst mal wiederholt und dann nach dem Zufallsprinzip auswählt.
Erik der Outgolfer

16

R , 25 Bytes

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

Probieren Sie es online!

Erläuterung:

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

Nimmt eine Probe von seiner Größe 1ohne Ersatz mit Gewichten s; Diese werden neu skaliert, um Wahrscheinlichkeiten zu sein.

Verwenden Sie diesen Link, um die Verteilung zu überprüfen .


Du hast mich um 9 Monate geschlagen! : D
JayCe

@ JayCe heh, mein einziger Vorteil gegenüber dir scheint "zuerst" zu sein, da du ganz der Golfer bist! :-)
Giuseppe

13

Pyth , 4 Bytes

OsmR

Probieren Sie es hier aus.

Dank @Jakube wurde ein Byte mit einem eher ungewöhnlichen Ansatz gespeichert.

Pyth , 5 Bytes

Osm*]

Probieren Sie es hier aus!

Wie?

# 1

OsmR - Volles Programm.

   R - Rechte Karte ...
  m - ... Mit Karte. Dies erzeugt im Wesentlichen die Liste [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Dafür gebührt Jakube die Ehre!
 s - Abflachen.
O - Zufälliges Element von ^. Implizit anzeigen.

# 2

Osm *] - Volles Programm.

  m - Karte über die Eingabe.
    ] - Das aktuelle Element, d, umschlossen; [d].
   * - D-mal wiederholt.
 s - Abflachen.
O - Zufälliges Element. Drucken Sie das Ergebnis implizit aus.

1
Ich kann es in 4 machen. Soll ich es verderben, oder willst du es selbst finden?
Jakube

2
@ Jakube Warten Sie ein bisschen. Willst du sehen, ob ich es schaffen kann? Ist das so offensichtlich?
Mr. Xcoder

1
@Jakube Ok, ich werde pingen, wenn ich aufgebe.
Mr. Xcoder

1
OsmLoderOsmR
Jakube

1
@ Jakube Ooh das ist sehr schlau! Implizites Argument d, dann Karten düber einen Bereich ... Genie!
Erik der Outgolfer

8

CJam (9 Bytes)

q~_]ze~mR

Online-Demo . Dies ist ein vollständiges Programm, das Eingaben im CJam-Array-Format auf stdin übernimmt und das ausgewählte Element auf stdout ausgibt.

Präparation

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

1
Ein so kraftvoller Golf für eine so einfache Aufgabe.
Erik der Outgolfer

7

Perl 6 , 20 Bytes

1 Byte dank @Brad Gilbert b2gills gespeichert.

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

Probieren Sie es online!

Dies benötigt 1 Listenargument. Wir haben 2 Kopien dieser Liste mit dem xxOperator gepackt. So erhalten @_ Zxx@_wir eine Liste, in der das Element mal xdargestellt xwird. Es wird dann zu Bageiner Sammlung gezwungen , in der Objekte zusammen mit der Häufigkeit ihres Auftretens in der Sammlung gespeichert werden. Schließlich wählen wir ein zufälliges Element aus dieser Sammlung mit aus pick, das die Zählungen berücksichtigt und The Right Thing ™ ausführt.


Dies kann verkürzt werden{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills

@ BradGilbertb2gills, leider funktioniert das nicht. Es wird eine Tüte aus den Paaren gemacht (es gäbe also nicht "1" einmal, "2" zweimal usw., sondern "1 => 1" einmal, "2 => 2" auch einmal usw. - nicht das, was ich will) . Das liegt daran, dass Komponisten keine Nötigen sind, wie in diesem Adventskalender erläutert .
Ramillies

@ BradGilbertb2gills, aber trotzdem danke, du hast mir geholfen, einige Plätze hier und auch bei anderen Herausforderungen auszuspielen!
Ramillies

Ich meinte{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills

Aah, ich verstehe. Warum ist es mir nicht eingefallen ... :-) Danke.
Ramillies


5

MATL , 8 6 Bytes

tY"1Zr

Probieren Sie es bei MATL Online!

Erläuterung

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];}

Try it online!


Could you add an explanation? I'm trying to understand why the for(r*=Math.random();;) is needed, or if all you need is r*=Math.random().
Ayb4btu

@Ayb4btu Without the for(;;) loop this would require a second (never reached) return statement after the for(int i:a)... to satisfy the compiler - which would be 3 bytes longer.
Nevay

Ah, of course, your for(int i:a) is like a foreach in C#. I had the same problem, but just used a for that continually loops. Your new answer intrigues me, I might try and pilfer some of your ideas.
Ayb4btu

3

J, 8 7 8 bytes

The 7 byter is invalid; I'll revert this to a previous edit when I get back to my computer in a day or two.

Try it online!

?@+/{#~

:( selecting random elements from an array is costly.

8 bytes

#~{~1?+/

9 bytes

(1?+/){#~

Explanation

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

?@+/ is (?@+)/; I'm afraid you'll have to bump that up to 8 again…
FireFly

@FireFly I should've tested it more, good catch.
cole

3

JavaScript (ES6), 50 bytes

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

Hopefully it's apparent how this works, but I'll explain it here anyway. It sorts the integers in descending order, then chooses one at random with a beta distrubution (1/2,1).


I don't think this will have the correct distribution. My tests show that with a=[4,1,5], you'll get about 18% 1, 24% 4, and 58% 5, which suggests you'll get that distribution with any input of length 3.
Giuseppe

That seems correct to me. Higher integer, higher probability.
kamoroso94

Oh, I see. I misread the question. Excellent solution, +1!
Giuseppe


2

PowerShell, 27 bytes

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

Try it online!

Takes input $args[0] as a literal array. Loops through each element |%{...} and each iteration constructs a new array ,$_ of $_ elements -- e.g., for 4 this will create an array @(4,4,4,4). Those array elements are then piped into Get-Random which will pluck out one of the elements with (pseudo) equal probability. Since, e.g., for @(4,1,5) this gives us @(4,4,4,4,1,5,5,5,5,5) this satisfies the probability requirements.


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];}

Try it online!

An extra 18 bytes for using System.Linq;

Acknowledgements

11 bytes saved thanks to Nevay, whose random number implementation was a lot more concise (as well as being an int instead of a double).

Degolfed

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

Explanation

Get a random number, r, between 0 and sum of elements. Then at each iteration subtract the current element from r. If r is less than 0, then return this element. The idea is that there are bigger portions of the random number for the larger numbers in the array.


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

2

Japt, 7 bytes

ËÆD
c ö

Test it here


Explanation

Implicit input of array U.

Ë

Map over the array passing each element through a function where D is the current element.

ÆD

Generate an array of length D and fill it with D.

c

Flatten.

ö

Get a random element.



1

Perl, 31 bytes

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

This assumes the input to be command line arguments. Note that it may run out of memory if the numbers are large.




1

Charcoal, 12 bytes

F⪪θ;FIι⊞υι‽υ

Try it online! Link is to verbose version of code. Since Charcoal tries to be too clever, I'm having to use semicolon-delimited input for the array. Explanation:

  θ             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 thanks to @Justin Mariner

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

Example code snippet

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


You can sum by using eval(a.join`+`) instead of reduce.
Justin Mariner

If you're ok with ES7+ you can use: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+)) and call with input::[].find(...)
Downgoat

1

Haskell, 78 77 bytes

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

Try it online! Usage example: f [1,99] probably yields 99.

Explanation:

  • f takes a list of integers l and returns the randomly selected integer as IO Int.
  • l>>= \n->n<$[1..n] constructs a list with each element n repeated n times.
  • randomRIO(0,sum l-1) yields an integer in the range from 0 to the length of the list of repeated elements, which is exactly the sum of all elements, minus one to avoid a out of bound exception.

Bonus: 85 byte point-free version

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

Try it 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 thanks to @Nevay.

Uses a similar approach as @ErikTheOutgolfer's Jelly answer, by adding n times the item n to the list, and then select one randomly from that list.

Explanation:

Try it here.

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
You can move the #shuffle call into the for loop to save 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay

@Nevay Thanks! Shuffling the List after every iteration is pretty inefficient, but what do we care about efficiency, warnings and such when we can get rid of one additional pesky byte. ;p
Kevin Cruijssen

1

Dyalog APL, 8 bytes

/⍨⌷⍨1?+/

Try it online!

How?

  • /⍨, n copies of n for each n in the argument.
  • ⌷⍨, at the index of
  • 1?, a random value between 1 and
  • +/, the sum of the argument

1

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

Approach inspired by Erik the Outgolfer's Jelly answer. Relies on ⎕IO being 0 instead of 1, which is the default for GNU APL (sort of +5 bytes for ⎕IO←0).

-3, -2 bytes thanks to @Zacharý

function form

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

Anonymous lambda form

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

For the explanation, I will use to represent the argument passed to the function, but it is equivalent to R in the form.

⍵∘.⍴⍵ computes the outer product on the list using the reshape () operator. Effectively, this creates a table (like a multiplication table) but instead of multiplying, it repeats the element in the column a number of times equal to the element in the row. For the example given in the question, this is:

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⍉⍵∘.⍴⍵ transposes the matrix and returns just the main diagonal. This gives us just the parts where the row and column in ⍵∘.⍴⍵ were the same i.e. we repeated the number a number of times equal to its value. For the example, this is:

4 4 4 4  1  5 5 5 5 5

turns its argument into a list. Using the transpose () operator, we got a vector containing 3 vectors. Enlist () turns it into a single vector containing all the elements.

S←... assigns this new vector to vector S. ⍴S gives us the length of that list. ? is the random operator, so ?⍴S gives us a random number between 0 and the length of the list (exclusive) (this is why it relies on ⎕IO being 0; otherwise it's between 1 and the length, inclusive). S[...] returns the element at the given index.


You don't need Q, since you never use it. And IIRC you can remove the newline before the del (little triangle-thing marking the end of the function.)
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.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.