14
\$\begingroup\$

Inspired by this question

Task:

Given integers X and Y:
Randomly select an int in 1..Y (inclusive), X times. This selection is to be performed without replacement until all values in 1..Y are exhausted, at which point they all become replaced at the same time. This could happen several times.

X may (but is not guaranteed to) be greater than Y and always greater than 0.

Y is greater than 0.

"random" means that for each selection, each value not yet exhausted has about an equal chance of being selected. Relevant defaults (notably, no xkcd 221) apply.

You may not select in 0..Y or any other range instead.

Output format is flexible (array, ordered list, stdout) but each Y-length run may not be differentiable. For example, it is forbidden to output a newline after each Y-wide selection run if selections aren't normally separated by newlines.

examples (obviously since this is the actual results may vary):

x=5, y=10 -> [ 10, 6, 2, 8, 9 ]
x=10, y=10 -> [ 5, 3, 1, 7, 6, 4, 10, 8, 9, 2 ]
x=15, y=10 -> [ 5, 6, 2, 4, 9, 3, 8, 1, 7, 10, 7, 1, 2, 9, 3 ]

This is .

asked Apr 22 at 15:06
\$\endgroup\$
7
  • 1
    \$\begingroup\$ By 1..Y, do you mean including 1 and Y? Also, can we use a zero-indexed range (0..Y-1)? \$\endgroup\$ Commented Apr 22 at 15:39
  • \$\begingroup\$ Possible duplicate \$\endgroup\$ Commented Apr 22 at 15:47
  • 2
    \$\begingroup\$ I'm not sure this should be closed as a duplicate of that since the requirements there limit the bag to exactly seven items, and so most of the answers use that fact. Answers here would, however, be pretty similar to answers there, so maybe it should be a duplicate? Since this was closed by one user vote and the community bot I'll cast a reopen vote (which will reopen it!) and see what the community decide. \$\endgroup\$ Commented Apr 22 at 18:54
  • \$\begingroup\$ (Also, that one allows answers to draw ad-infinitum.) \$\endgroup\$ Commented Apr 22 at 19:08
  • 1
    \$\begingroup\$ @madeforlosers examples added. \$\endgroup\$ Commented Apr 25 at 7:50

25 Answers 25

8
\$\begingroup\$

JavaScript (ES7), 79 bytes

Expects (y)(x).

y=>g=(x,n,i=Math.random()*y)=>x?n>>i&1?[-~i,...g(x-1,n^1<<i)]:g(x,n||2**y-1):[]

Try it online!

Commented

y => // outer function taking y
g = ( // inner recursive function taking:
 x, // x
 n, // n = bit-mask, initially undefined
 i = Math.random() // i = random value in [0, y[
 * y // (implicitly floored in bitwise operations)
) => //
x ? // if x is not zero:
 n >> i & 1 ? // if the i-th bit of n is set:
 [ // update the output array:
 -~i, // append floor(i) + 1
 ...g( // do a recursive call:
 x - 1, // decrement x
 n ^ 1 << i // clear the i-th bit of n
 ) // end of recursive call
 ] // end of array update
 : // else:
 g( // do a recursive call:
 x, // pass x unchanged
 n || // pass either n unchanged,
 2 ** y - 1 // or with y bits set if cleared
 ) // end of recursive call
: // else:
 [] // stop
answered Apr 22 at 21:18
\$\endgroup\$
2
  • 5
    \$\begingroup\$ Gratz on 200K :) \$\endgroup\$ Commented Apr 23 at 12:02
  • 1
    \$\begingroup\$ @JonathanAllan Thank you! \$\endgroup\$ Commented Apr 23 at 15:17
7
\$\begingroup\$

Python 3, 77 bytes

f=lambda x,y:x*[x]and sample(range(1,y+1),y)[:x]+f(x-y,y)
from random import*

Try it online!

-3 bytes thanks to Jonathan Allan

answered Apr 22 at 15:27
\$\endgroup\$
0
5
\$\begingroup\$

Ruby, 42 bytes

Rather conveniently, calling sample with a number bigger than the length of the array shuffles it (as if you called it with the array length), saving bytes over having to get the minimum of x and y.

f=->x,y{x>0?[*1..y].sample(x)+f[x-y,y]:[]}

Try it online!

answered Apr 23 at 0:42
\$\endgroup\$
5
\$\begingroup\$

Julia, 90 bytes

+(X,Y)=begin Z=[];map(x->begin(Z==[])&&(Z=[1:Y...]);popat!(Z,rand(1:length(Z)))end,1:X)end

Attempt This Online!

Grateful that rand() is in Base.

ATO doesn't have StatsBase but the following is 85 bytes:

using StatsBase
+(x,y)=[sample([1:y...],min(x,y);replace=false);(x>y) ? (x-y+y) : []]
answered Apr 23 at 18:58
\$\endgroup\$
1
  • 2
    \$\begingroup\$ 65 bytes small improvements: +(X,Y) => X+Y, begin ... ; ... end => ( ... ; ... ), 1:length => keys \$\endgroup\$ Commented Apr 24 at 20:09
4
\$\begingroup\$

Jelly, 5 bytes

Ẋ{ⱮFḣ

A dyadic Link that accepts the range size, \$Y\$, on the left and the desired count, \$X\$, on the right and yields a list of the \$X\$ draws from \$[1,Y]\$.

Try it online!

How?

Shuffle each of \$X\$ copies of \$[1,Y]\$, flatten this list of lists, and then only keep the first \$X\$.

Ẋ{ⱮFḣ - Link: non-negative integer, Y; non-negative integer, X
 Ɱ - map across {v in [1..X]} with - f(Y, v):
 { - using Y as the arguments - f(Y, Y):
Ẋ - shuffle {[1..Y]}
 F - flatten
 ḣ - head to index {X}
answered Apr 22 at 19:38
\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 43 bytes

Table[##&@@RandomSample@Range@#2,#]~Take~#&

Try it online!

Input [X, Y].

answered Apr 23 at 4:04
\$\endgroup\$
4
\$\begingroup\$

APL+WIN, 20 bytes.

Prompts for y followed by x.

x↑∊y? ̈(⌈(x←⎕)÷y)⍴y←⎕

Try it online! Thanks to Dyalog Classic

answered Apr 23 at 12:49
\$\endgroup\$
4
\$\begingroup\$

Google Sheets, (削除) 103 (削除ここまで) 91 bytes

-12 bytes thanks to Jonathan Allan

Expects \$X\$ in A1 and \$Y\$ in A2.

=QUERY(REDUCE(,SEQUENCE(A1),LAMBDA(a,_,{a;SORT(SEQUENCE(A2),RANDARRAY(A2),)})),"limit "&A1)

Stacks on top of each other \$X\$ randomized sequences of numbers from \1ドル..Y\$ and constrains the result to the first \$X\$ values.

answered Apr 22 at 20:51
\$\endgroup\$
1
  • 2
    \$\begingroup\$ More sequences internally, but the same result: CEILING(A1/A2) -> A1. \$\endgroup\$ Commented Apr 25 at 9:32
4
\$\begingroup\$

TI-BASIC (TI-83 Plus), (削除) 72 (削除ここまで) (削除) 67 (削除ここまで) 65 bytes

-5 bytes thanks to MarcMush

Input A
Input B
B→dim(L1
For(N,1,A
If not(max(L1
cumSum(1 or L1→L1
Repeat L1(E
randInt(1,B→E
End
Disp L1(E
0→L1(E
End

TI calculators with OS 2.53MP (and the TI-84+/SE) have a RandIntNoRep function that would make this a lot easier, but I don't have one of those anymore. gotta look into upgrading

answered Apr 24 at 16:28
\$\endgroup\$
4
  • \$\begingroup\$ you can use Repeat instead of While to spare the 1 line and combine with not(L1(E \$\endgroup\$ Commented Apr 24 at 20:15
  • \$\begingroup\$ you can save 2 extra bytes by using named lists (codegolf.stackexchange.com/a/143898) \$\endgroup\$ Commented Apr 27 at 12:15
  • \$\begingroup\$ MarcMush can you show me the code for this? can't seem to get it to work / save any bytes \$\endgroup\$ Commented Apr 29 at 13:03
  • \$\begingroup\$ you can do {0→A which is the same as {0→ʟA but ʟA(1 cannot be shorten. L1 is 2 bytes and ʟ is 1 only \$\endgroup\$ Commented Apr 30 at 12:06
3
\$\begingroup\$

Vyxal, 7 bytes

ẋvÞc/of0Ẏ

Try it Online!

Taking a L here because shuffle is two bytes and because input cycling works against me

answered Apr 23 at 1:32
\$\endgroup\$
3
\$\begingroup\$

Charcoal, 27 bytes

NθFN«F∧¬υθ⊞υ⊕κ≔⟦‽υ⟧ι≔−υιυIι

Try it online! Link is to verbose version of code. Takes inputs in the order Y, X. Explanation:

Input Y.

FN«

Repeat X times.

F∧¬υθ⊞υ⊕κ

If all of the values are exhausted, replace all the values 1..Y.

≔⟦‽υ⟧ι

Pick a random value and wrap it in a list.

≔−υιυ

Perform list subtraction to remove it from the values.

Output it. (As a list, this outputs each value on its own line.)

answered Apr 23 at 9:26
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 8 bytes

иL€.r ̃1£

Inputs in the order \$X,Y\$. Outputs as a list.

Try it online.

A program derived from my answer to the related challenge would be 1 byte longer:

FIL.r) ̃ć,

Inputs in the order \$X,Y\$. Outputs each value on a separated newline.

Try it online.

Explanation:

и # Repeat the second (implicit) input `Y` the first (implicit) input `X`
 # amount of times as list
 L # Convert each inner `Y` to a list in the range [1,Y]
 € # Map over each of those inner [1,Y]-lists
 .r # Randomly shuffle it
 ̃ # Flatten this list of lists
 1£ # Only keep the first input `Y` amount of leading values
 # (after which this list is output implicitly)
F # Loop the first (implicit) input `X` amount of times:
 IL # Push a list in the range [1, second input Y]
 .r # Randomly shuffle it
 ) # Wrap everything on the stack into a list
 ̃ # Flatten it
 ć # Extract its head; push remainder-list and first item separately
 , # Pop and print this first item with trailing newline
answered Apr 23 at 9:57
\$\endgroup\$
2
  • 2
    \$\begingroup\$ The first one doesn't work if Y > 9. \$\endgroup\$ Commented Apr 23 at 12:02
  • \$\begingroup\$ @juanferrer Thanks for noticing! Should be fixed now. \$\endgroup\$ Commented Apr 23 at 12:32
3
\$\begingroup\$

Perl 5 -MList::Util=min -MList::MoreUtils=samples -ln, 54 bytes

map{say}samples min($_,$t//=<>),1..$_;($t-=$_)>0&&redo

Try it online!

answered Apr 23 at 14:44
\$\endgroup\$
3
\$\begingroup\$

Uiua 0.16.0-dev.1, (削除) (削除ここまで) 11 bytes SBCS

 ̃↙♭≡°⍆+1↯⤙⇡

Try on Uiua Pad!

Takes Y X on stack.

Explanation

 ̃↙♭≡°⍆+1↯⤙⇡
 +1↯⤙⇡ # X copies of range 1...Y
 ≡°⍆ # randomize each (literally "un"-"sort")
 ̃↙♭ # flatten and take the first X
answered Apr 23 at 15:24
\$\endgroup\$
3
\$\begingroup\$

PowerShell, 51 bytes

param($x,$y)for(;$x-gt0;$x-=$y){1..$y|random -c $x}

Try it online!

answered Apr 23 at 22:03
\$\endgroup\$
3
\$\begingroup\$

C# 10, (削除) 202 (削除ここまで) (削除) 154 (削除ここまで) 140 bytes

f=(x,y)=>{Random r=new();List<int> a=new();for(int i=-1;i<x/y;i++)a.AddRange(Enumerable.Range(1,y).OrderBy(x=>r.Next(y)));return a.Take(x);}

Accepts 2 ints and returns an IEnumerable<int>.

Try it on JDoodle.

Ungolfed:

Random r = new();
List<int> a = new();
for (int i = -1; i < x / y; i++) // Repeat 1 + x/y times:
 a.AddRange(Enumerable.Range(1, y).OrderBy(x => r.Next(y))); // Get the range 1-y, sort it randomly and append to list
Console.WriteLine(string.Join(',', a.Take(x))); // Take the first x numbers from list and print them

C# 12, (削除) 198 (削除ここまで) (削除) 150 (削除ここまで) 138 bytes

Shorter empty list initialiser ([] vs new()).

f=(x,y)=>{Random r=new();List<int> a=[];for(int i=-1;i<x/y;i++)a.AddRange(Enumerable.Range(1,y).OrderBy(x=>r.Next(y)));return a.Take(x);}

Edit: Turned it into a function thanks to Themoonisacheese's comment.

answered Apr 23 at 13:16
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Fyi, you're allowed to sumbit functions that assume they are passed the correct type, and return their result instead of printing it, that's usually shorter, especially in C# :) \$\endgroup\$ Commented Apr 23 at 13:24
  • \$\begingroup\$ Well, if that's the case, I'll have to go and edit all my answers! xD Thanks, I'll update the question. \$\endgroup\$ Commented Apr 23 at 13:43
2
\$\begingroup\$

Maple, 112 bytes

proc(x,y)L:=[$y];S:=();to x do r:=rand(1..nops(L))();S,=L[r];L:=subsop(r=(),L);if L=[] then L:=[$y] fi od;S end;
proc(x,y)
L:=[$y]; # initialize list to [1..y]
S:=(); # initialize output sequence to NULL
to x do
 r:=rand(1..nops(L))(); # find random index into current list
 S,=L[r]; # augment sequence with new value
 L:=subsop(r=(),L); # remove value from list
 if L=[] then L:=[$y] fi # reset list if empty
od;
S; # return sequence
end;

I thought a recursive function would be shorter, but it wasn't

answered Apr 24 at 17:10
\$\endgroup\$
2
\$\begingroup\$

C (gcc), 99 bytes

f(x,y){int i,a[y],n=0;for(;x--;a[i]=a[--n]){
if(!n)for(;n<y;a[n++]=n);printf("%d ",a[i=rand()%n]);}}

Try it online!

A simple algorithm that (re)generates the pool when empty, and swaps each picked value with the shrinking end.

answered Apr 24 at 22:07
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 97 bytes \$\endgroup\$ Commented Apr 26 at 4:05
2
\$\begingroup\$

CASIO BASIC (CASIO fx-9750GIII), (削除) 92 (削除ここまで) 76 bytes

?→A
?→B
{0→List1
For 1→N To A
Not Max(List1⟹Seq(K,K,1,B,1→List1
Do
RanInt#(1,B
LpWhile Not List1[Ans
List1[Ans◢
0→List1[Ans
Next

I think this is right

input x first, then y

try a longer version online at basic.crevola.org

answered Apr 24 at 15:32
\$\endgroup\$
2
\$\begingroup\$

R, (削除) 44 (削除ここまで) 36 bytes

\(x,y)sapply(1:x,\(i)sample(y))[1:x]

Attempt This Online!

answered Apr 25 at 6:04
\$\endgroup\$
2
\$\begingroup\$

Arturo, 46 bytes

$[x y]->take flatten [email protected]:[email protected]=>shuffle x

Try it!

answered Apr 25 at 22:41
\$\endgroup\$
2
\$\begingroup\$

Pharo, 63 bytes

[:x :y|((1to:x)flatCollect:[:x|(1to:y)asArray shuffle])first:x]
answered Apr 26 at 1:01
\$\endgroup\$
1
\$\begingroup\$

Google Sheets, 82 bytes

=query(tocol(map(1:1,lambda(_,sort(sequence(A3),randarray(A3),))),,1),"limit "&A2)

Put \$X\$ in cell A2, \$Y\$ in cell A3 and the formula in cell B2.

screenshot

(cheats a bit)

answered Apr 25 at 16:29
\$\endgroup\$
1
\$\begingroup\$

Zsh + GNU coreutils, 32 bytes

(repeat 1ドル shuf -i1-2ドル)|head -1ドル

Expects x, y as arguments.

Attempt This Online!

answered Apr 27 at 17:29
\$\endgroup\$
1
\$\begingroup\$

APL(Dyalog Unicode), (削除) (削除ここまで)14 bytes SBCS

∊⊢?⍨ ̈|⍨,⍨⌊⍤÷⍴⊢

X is the left argument, Y is the right.

Try it on APLgolf!

Explanation

 ⊢ right argument, Y
 ⍴ reshape
 ÷ divide
 ⍤ postprocess
 ⌊ floor
 ⌊⍤÷ floor division; X//Y
 ⌊⍤÷⍴⊢ repeat Y (X//Y) times
 ⍨ swap left and right arguments
 , concatenate
 ,⍨ append left argument to the end 
 ⍨ 
 | modulo
 |⍨ Y%X (arguments are swapped)
 |⍨,⍨⌊⍤÷⍴⊢ repeat Y while the sum is less than X, append the remainder
 ̈ each
 ⍨ 
 ? deal: A?B returns A different numbers in range 1..B
 ⊢ 
 ⊢?⍨ ̈ for each number N on the right: deal N times in range Y
 ⊢?⍨ ̈|⍨,⍨⌊⍤÷⍴⊢ solution but as vector of vectors: new subvector starts after exhausting all values in 1..Y
∊ enlist: make one vector from all values in order
∊⊢?⍨ ̈|⍨,⍨⌊⍤÷⍴⊢ solution
answered May 9 at 18:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.