# Generating unique random number lists

I am new in programming. I have an array containing, let's say 20 elements and first I want to randomly select two elements from it and record them. Then I will select two elements from the array of twenty elements again and record them. The process continues, let's say 10 times and in these 10 draws, I do not want to repeat any of the two elements that I have already drawn.

I used RandomSample to generate random numbers.

j = 0;
For[i = 0, i < 2, i++,
Yarray[j] = RandomSample[Range[8], 2];
Print[Yarray[j]];
j++;]

-
Welcome to the site Daniel. That's a good question. – Mr.Wizard Jun 30 '12 at 14:28

You can do this in a number of ways:

• Use RandomSample to generate a random list with twice the sample size you need and partition:

Example: Draw 5 random pairs from Range[20]:

 Partition[RandomSample[Range[20], 10], 2]
(*  result:  {{20, 14}, {19, 8}, {5, 1}, {12, 15}, {17, 2}} *)

• Nest a composite function that draws one pair and deletes it from the base list sequentially:

Example: Draw 5 random pairs from the list of letters {a,...,z}:

samples = {};
Nest[( samples = Append[samples, RandomSample[#, 2]];
Complement[#, Flatten@samples]) &,  CharacterRange["a", "z"], 5];
samples
(* result: {{"m", "c"}, {"g", "h"}, {"r", "l"}, {"n", "x"}, {"u", "a"}} *)

-

Given

elements = Table[Unique["el"], {20}]


{el3, el4, el5, el6, el7, el8, el9, el10, el11, el12, el13, el14, \ el15, el16, el17, el18, el19, el20, el21, el22}

What you want is equivalent to

Partition[RandomSample[elements], 2]

{{el22, el17}, {el12, el6}, {el5, el19}, {el7, el18}, {el9,
el4}, {el13, el21}, {el11, el3}, {el10, el16}, {el14, el15}, {el8,
el20}}


If you want less sets (say 3), you can always do

Partition[RandomSample[elements], 2]~Take~3


{{el4, el18}, {el10, el8}, {el19, el21}}

or more efficiently

Partition[RandomSample[elements, 2 3], 2]


However, if we want to implement your algorithm as you described it (3 times in this example)

Reap[Nest[Complement[#, Sow@RandomSample[#, 2]] &, elements, 3]][[2, 1]]


I'll break this down. Complement[#, Sow@RandomSample[#, 2]] &. This is a function that takes one argument. The argument should be a list with the remaining elements. It takes 2 random elements of those (RandomSample[#, 2]) and Sows them (puts them aside for later recollection). Then, it returns the original list without those 2 elements.

We apply that function to the whole list of elements, 3 times (Nest[function, elements, 3])

Finally, we collect the stuff we put aside in the process (Reap[...][[2, 1]])

-

Here is one possible solution:

SetAttributes[draw, HoldFirst]

draw[var_, n_] /; n <= Length@var :=
# &[Take[var, n], var = Drop[var, n]]


Initialize the set:

set = RandomSample@Range@20;


Draw your elements. I use Table rather than the For loop.

Table[
draw[set, 2],
{10}
]


Output:

{{7, 16}, {2, 11}, {17, 14}, {9, 12}, {10, 3},
{15, 13}, {19, 1}, {20, 6}, {8,4}, {18, 5}}


Confirm that set is now empty:

set

{}


So how does this work? Let me break it down. The set of shuffled numbers is stored as an assignment to a Symbol named set. To handle this Symbol itself my function needs a Hold* attribute. I choose HoldFirst:

SetAttributes[draw, HoldFirst]


I then define a function using pattern matching that takes two parameters: var and n, and I include a check on these elements with Condition (/;). I want my function to do two things:

1. take the first two elements from the set given as var. This is done with Take[var, n]

2. remove these from set itself. This can be done with var = Drop[var, n]

Since I want to return the result of the first operation, but it must be performed before the second, I use a "pure function" (using Function and Slot): # & which simply returns (only) the first argument it is given, and then give each of the operations above as arguments:

draw[var_, n_] /; n <= Length@var :=
# &[Take[var, n], var = Drop[var, n]]

-
+1 for the pass-by-reference method! – István Zachar Jul 1 '12 at 8:45
@István Thanks. I decided that taking the OP's question literally made for a much more interesting answer. – Mr.Wizard Jul 1 '12 at 8:50