Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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

share|improve this question
2  
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 at 20:44
    
@Szabolcs. Your comment should be posted as answer. –  m_goldberg Feb 21 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 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 at 4:21

1 Answer 1

up vote 3 down vote accepted

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.

share|improve this answer
    
Thanks for the answer! Do you know why is latter faster? –  mete Feb 21 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 at 1:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.