# Recursion when randomizing elements in a list

I want to randomize certain elements of a list; Since the code

list = {a, b, c, d, e, f, g};
list[[{1, 3, 5}]] = RandomSample@list[[{1, 3, 5}]];
list


works fine, I was trying to see if I could speed up things a little bit and have only one call to list[[{1,3,5}]] using a pure function

The code

list = {a, b, c, d, e, f, g};
(# = RandomSample@#) &[list[[{1, 3, 5}]]];
list


will trigger an infinite recursion. I know that the function evaluates the argument before passing to the function, but the infinite recursion still confuses me.

Any thoughts? Thanks

-
The problem with the pure function approach is that this pure function doesn't have a HoldAll attribute so list[[{1, 3, 5}]] is evaluated before it is substituted in #, so you end up with {a,c,d} = RandomSample[{a,c,d}] (i.e. creating cyclic definitions for these three symbols) instead of the correct list[[{1,3,5}]] = RandomSample[{a,c,d}]. To fix this, use Function[x, x=RandomSample[x], HoldAll]. However, this approach won't help in speeding up your code. –  Szabolcs Feb 20 '14 at 20:44
@Szabolcs. Your comment should be posted as answer. –  m_goldberg Feb 21 '14 at 0:11
Is the question just about the recursion behavior, or is there an over-arching goal, e.g. creating some large number of such lists rapidly? –  rasher Feb 21 '14 at 4:12
Both: my question was initially on the recursion, but the final goal would be to be able to create a large number of (fairly big) such lists –  mete Feb 21 '14 at 4:21

As to the faster generation part of your query, something like the following should be useful if you're needing a large number of tinkered lists:

list = {a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p};
positions = {3, 5, 7, 9, 11, 14, 15};
numtomake = 100000;

(** naive generation **)
Table[(list[[positions]] = RandomSample@list[[positions]];
list), {numtomake}]; // Timing

(** precomputing samples *)
(elements = list[[positions]];
listTargets = ConstantArray[list, numtomake];
permutations = Table[RandomSample[elements], {numtomake}];
listTargets[[All, positions]] = permutations;) // Timing

(* 2.293215 *)
(* 0.936006 *)


So about 2.5X faster in my minimal tests, probably better as list size/number of possible permutation candidates, and number of lists needed increase.

-
Thanks for the answer! Do you know why is latter faster? –  mete Feb 21 '14 at 19:46
@user2397318: Pretty standard MMA fare: any time you can do things in "bulk" (the copy with "All") vs separate calls, it will be faster, and for some things (e.g. certain array operations) MMA will use sorcery under the covers (like divide-and-conquer) to speed things up. –  rasher Feb 22 '14 at 1:02