16
$\begingroup$

I'm trying to do this:

i1 = 1;
i2 = 1;

RandomChoice[{
  (i1 = i1 + 1),
  (i1 = i1 - 1),
  (i2 = i1 + 1),
  (i2 = i2 - 1)}]

In order to chose randomly which variable is going to be incremented or decremented - but it's not working. I've also tried with -- and ++ but I had the same problem. I am clueless about what may be the problem.

$\endgroup$
0

8 Answers 8

17
$\begingroup$

May be the most compact approach:

Hold[i1++, i1--, i2++, i2--][[RandomInteger[{1, 4}]]]
$\endgroup$
0
11
$\begingroup$

I'd do :

choices = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
{i1, i1} = {i1, i2} + RandomChoice[choices]
$\endgroup$
11
$\begingroup$

Putting Increment or Decrement in third argument of Extract:

Extract[expr, list, h]

extracts parts of expr, wrapping each of them with head h before evaluation.

{i1, i2} = {1,1};
vars = Hold[i1, i2];

Extract[
  vars
  , RandomInteger[{1, Length@vars}]
  , RandomChoice[{Increment, Decrement}]];
$\endgroup$
0
8
$\begingroup$

The problem is that the expressions inside RandomChoice[list] are evaluated before one of the elements in the list is picked. You can use the functions Hold and ReleaseHold to force the evaluation of the elements in the list to occur after the random choice like this:

ReleaseHold@RandomChoice[{Hold[i1++], Hold[i1--], Hold[i2++], Hold[i2--]}];
$\endgroup$
8
$\begingroup$

There are already many great answers here. Most of then work by holding various things unevaluated. I'd like to propose an alternative of sorts.

If we use indexed Symbols we can avoid unwanted premature evaluation without Hold or similar. Working with lists of "keys" is far easier than working with lists of assigned Symbols.

i[1] = 1;
i[2] = 1;

i[#@{1, 2}] += #@{-1, 1} & @ RandomChoice

That's two calls to RandomChoice, compressed with Function, one for the list of keys and one for the list of addends. Generalized:

roff[s_, keys_, os_, f_: RandomChoice] := s[f@keys] += f@os

Now:

i[_] = 1;

Do[
 roff[i, {"a", "b", "c"}, {-7, -3, 2, 4, 6}],
 {50}
]

i /@ {"a", "b", "c"}
{-7, 9, -3}

Note that you could use any other sampling function besides RandomChoice.

Or taking it in a different direction:

sampleApply[s_, keys_, fns_, R_: RandomChoice] := R[fns] @ s[R@keys]

j[_] = 0;

Do[
 sampleApply[j, Range@5, {Increment, Decrement}],
 {100}
]

Array[j, 5]
{3, -4, 2, 1, -6}

I hope these examples illustrate the flexibility and convenience of this approach.

$\endgroup$
1
  • 1
    $\begingroup$ Avoiding Hold induced headache is always good +1 $\endgroup$
    – ssch
    Commented Sep 12, 2013 at 18:53
5
$\begingroup$

Switch[RandomInteger[3], 0,++i1, 1,--i1, 2,++i2, _,--i2]

$\endgroup$
2
$\begingroup$

This is a more general approach, already made to a function: holdRandomChoice chooses randomly one of the listed commands without any of the others being evaluated:

SetAttributes[holdRandomChoice, HoldAll];
holdRandomChoice[list__] := Module[{x = Unevaluated@list},
   Part[x, RandomInteger@{1, Length@x}]];

Clear[i];
holdRandomChoice[Print[i = 1], Print[i = 2], Print[i = 3]]
i
During evaluation of In[1]:= 2

Out[4]= 2

Note that none of the other commands got printed.

$\endgroup$
2
  • $\begingroup$ FYI: you don't need Unevaluated or Module here; it would be a bit cleaner to use: Part[#, RandomInteger@{1, Length@#}] & @ Hold[list] $\endgroup$
    – Mr.Wizard
    Commented Sep 12, 2013 at 19:44
  • 3
    $\begingroup$ Actually, I would just write: holdRandomChoice[list__] := ReleaseHold @ RandomChoice @ Thread @ Hold @ {list} $\endgroup$
    – Mr.Wizard
    Commented Sep 12, 2013 at 19:46
1
$\begingroup$

a variation on tom's answer:

ReleaseHold@RandomChoice[{
     Hold[i1 += RandomChoice[{-1,1}]],
     Hold[i2 += RandomChoice[{-1,1}]] }]

which may be useful since it can be generalised, eg.:

ReleaseHold@RandomChoice[{
     Hold[i1 += RandomVariate[NormalDistribution[0, 3]]],
     Hold[i2 += RandomVariate[NormalDistribution[0, 3]]]}]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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