MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Challenge!

> 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.


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

  • Prev by Date: Re: simplex tableau help wanted
  • Next by Date: Re: Challenge!
  • Previous by thread: Re: Challenge!
  • Next by thread: Re: Challenge!