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.