22
\$\begingroup\$

This challenge is rather simple:
You are given an array of positive (not including 0) integers, and have to select a random element from this array.

But here's the twist:
The probability of selecting an element is dependent on the value of the integer, meaning as the integer grows larger, the probability of it to get selected does too!

Example

You are given the array [4, 1, 5].

The probability of selecting 4 is equal to 4 divided by the sum of all elements in the array, in this case 4 / ( 4 + 1 + 5 ) = 4 / 10 = 40%.
The probability of selecting 1 is 1 / 10 or 10%.

Input

An array of positive integers.

Output

Return the selected integer if using a method, or directly print it to stdout.

Rules

  • This is so shortest code in bytes in any language wins.
  • Standard loopholes are forbidden.
\$\endgroup\$
1
  • \$\begingroup\$ Is [4, 1, 4] a valid input and, if so, should the odds of outputting 4 be 4/5, 4/9 or 8/9? \$\endgroup\$
    – Sara J
    Mar 13 at 21:15

38 Answers 38

1
2
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Really appreciate the explanation, thanks! \$\endgroup\$
    – Ian H.
    Sep 17, 2017 at 10:24
1
\$\begingroup\$

Vyxal, 3 bytes

ẋf℅

Try it Online!

  ℅ # Choose a random element of
ẋ   # Each element n in the array repeated n times
 f  # Flattened
\$\endgroup\$
1
\$\begingroup\$

Uiua SBCS, 8 bytes

⊡⌊×⚂⧻.▽.

Try it!

⊡⌊×⚂⧻.▽.
      ▽.  # repeat each array item <itself> times
    ⧻.    # length
  ×⚂      # times random unit
 ⌊        # floor
⊡         # pick
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice, that’s what I had too \$\endgroup\$
    – noodle man
    Mar 11 at 18:44
1
\$\begingroup\$

Go (1.22+ only), 116 bytes

import."math/rand"
func f(s[]int)int{A:=[]int{}
for _,e:=range s{for range e{A=append(A,e)}}
return A[Intn(len(A))]}

Attempt This Online!

Go (all versions), 121 bytes

import."math/rand"
func f(s[]int)int{A:=[]int{}
for _,e:=range s{for i:=0;i<e;i++{A=append(A,e)}}
return A[Intn(len(A))]}

Attempt This Online!

Explanation

import."math/rand"
func f(s[]int)int{
// construct a slice with each element `n` repeated `n` times
A:=[]int{}
for _,e:=range s{for i:=0;i<e;i++{A=append(A,e)}}
// actually select the element
return A[Intn(len(A))]
}

Attempt This Online!

\$\endgroup\$
0
\$\begingroup\$

Clojure, 64 bytes

(defn a[i](rand-nth(reduce #(concat %(take %2(repeat %2)))[]i)))

Appends each item item number of times to a new list, then takes a random element.

Finally a clojure answer that's not incredibly much longer than other answers :D

\$\endgroup\$
0
\$\begingroup\$

05AB1E, 21 bytes

O/ždT6m/svy-D0‹s})1kè

Try it online!


Here's a weird implementation for you, uses microseconds on the system's CPU for the randomized seed.

O/                     # [.4,.1,.5] | Push prob distribution.
  ždT6m/               # ?????????? | 0 < x < 100000 divided by 100000.
        s              # [.4,.1,.5] | Swap...
         v             # For each prob in distribution...
          y-           # Remove from random number b/w 0 and 1.
            D0‹        # Dupe each, find if this number made the random number less than 0.
               s})     # Continue loop, swapping current random diff to the front of the stack.
                  1kè  # First instance of the random number going negative is our random return.
\$\endgroup\$
0
\$\begingroup\$

Clojure, 46 bytes

(fn[s](rand-nth(flatten(map #(repeat % %)s))))

Try it online!

The usual Clojure pain: simple idea, long-ass (for golfing) function names.

\$\endgroup\$
0
\$\begingroup\$

TI-BASIC, 20 bytes

Ans→L₁
SortD(L₁
L₁(1+int(rand²dim(L₁

Input and output are stored in Ans. If you see a box, L₁ is L1. Same algorithm as my JavaScript answer.

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.