> I have two lists of equal length M.
>
> I wish to generate a third list also of length M, where the i th element
> of this list is either the i th element of the first list, or the i th
> element of the second list.
>
> It should be equally probable that the new element be chosen from the
> first or second list.
>
> eg. I have a list {a,b,c,d,e,f,g}
> and another {A,B,C,D,E,F,G}
>
> valid answers would be:
> {a,B,C,d,e,F,G}
> {a,b,c,d,E,f,g}
> {A,B,C,D,e,f,G}
> etc.
Paul,
One way of looking at this is that you want to take corresponding
elements of the two lists, like a and A, and apply a function to
them, f[a, A], where f means "pick one of your arguments at random".
MapThread will do this: take two lists, feed their first arguments
to f, then feed their second arguments to f, and so on, giving you the
list of f-results at the end. A diagram makes it a little clearer
how you're gluing the two lists together with f:
{a1 , a2 , a3 , . . . , aM}
| | | |
f f f f
| | | |
{b1 , b2 , b3 , . . . , bM}
So let's use "glue" f that picks a random element:
In[7]:= list1 = {a, b, c, d, e, f, g}
Out[7]= {a, b, c, d, e, f, g}
In[8]:= list2 = {A, B, C, D, E, F, G}
Out[8]= {A, B, C, D, E, F, G}
In[9]:= MapThread[Part[{#1, #2}, 1 + Random[Integer] ]&, {list1, list2}]
Out[9]= {A, B, c, d, E, F, G}
Note that Random[Integer] is a short way of generating a random integer
0 or 1 (related: Random[Real] generates a random Real from 0 to 1, and
Random[Complex] generates a random Complex whose parts are real numbers
from 0 to 1).
We can make it easy to generate more random selections from the two by
making a delayed assignment to a variable 'randomSelection'. Any time
we evaluate 'randomSelection', like in a Table, we get a different
random selection from the two lists.
In[10]:= randomSelection := MapThread[Part[{#1, #2}, 1 + Random[Integer]
]&, {list1, list2}]
In[11]:= Table[randomSelection, {6}] //TableForm
Out[11]//TableForm= a b C D E F G
a B C d e F g
A B C D E f G
A b c D E F G
a b C D E f g
a B c D e F G
This method of storing a command or program in a symbol is given in
Roman Maeder's _Programming in Mathematica_ (2nd ed), section 5.5.3.
MapThread is happy to work with any number of lists, so we can use it to
randomly select from k lists instead of just 2, with essentially no
complications in the command. Here's the same technique applied to
seven lists:
In[18]:= lists = Array[a, {7, 5}] ; TableForm[lists]
Out[18]//TableForm= a[1, 1] a[1, 2] a[1, 3] a[1, 4] a[1, 5]
a[2, 1] a[2, 2] a[2, 3] a[2, 4] a[2, 5]
a[3, 1] a[3, 2] a[3, 3] a[3, 4] a[3, 5]
a[4, 1] a[4, 2] a[4, 3] a[4, 4] a[4, 5]
a[5, 1] a[5, 2] a[5, 3] a[5, 4] a[5, 5]
a[6, 1] a[6, 2] a[6, 3] a[6, 4] a[6, 5]
a[7, 1] a[7, 2] a[7, 3] a[7, 4] a[7, 5]
In[19]:= MapThread[Part[{##}, Random[Integer, {1, 7}]]&, lists]
Out[19]= {a[3, 1], a[2, 2], a[3, 3], a[7, 4], a[2, 5]}
A different method from MapThread is Table, and gives a command that
is equally short:
In[20]:= Table[Part[lists, Random[Integer, {1, 7}], i], {i, 5}]
Out[20]= {a[4, 1], a[4, 2], a[2, 3], a[1, 4], a[4, 5]}
I'm not sure which one holds up better in timing tests for either a
large number of lists, or lists with a large number of elements. It
would be interesting to do some tests.
Robby Villegas