[Date Index]
[Thread Index]
[Author Index]
Re: Call-by-reference from inside a function
*To*: mathgroup at smc.vnet.net
*Subject*: [mg72574] Re: [mg72568] Call-by-reference from inside a function
*From*: Daniel Lichtblau <danl at wolfram.com>
*Date*: Thu, 11 Jan 2007 02:12:17 -0500 (EST)
*References*: <200701091249.HAA21706@smc.vnet.net>
zac wrote:
> Dear Group,
>
> I'm in need of a function, which is called with one argument, a list.
> The function is to chose one element of the list randomly, AND modify
> the original list by removing the chosen element from it. My problem is
> that I cannot modify the global variable from inside the function. It
> is not a solution to return with a list such as:
> Return[{chosen_element, modified_local_list}], and than make an
> assignment outside the function.
> I'm thinking on some call-by-reference method, but as I've learned so
> far, there is no user-friendly way to do this, just some workarounds
> (which I don't know). Any suggestions?
>
> Istvan
>
> example code below:
>
> RandomChoseElem[list_List] := Module[
> {pos, elem},
> pos = Random[Integer, {1, Length[list]}];
> elem = list[[pos]];
> (* This is to be solved inside : *)
> (* global`list = Drop[global`list, {pos}]; *)
> Return[elem]
> ];
>
> set = {1, 2, 3, 4};
>
> RandomChoseElem[set]
As several responses noted, using HoldFirst or HoldAll will allow you to
do this.
I wanted to address an issue of efficiency. If you do this often on
large lists, you incur an O(n) hit each time from using Drop to rewrite
the list. Instead you can use a "shuffle" approach wherein you prepend
an element acting as a "counter", and swap the chosen element with the
counter current position at each step. This will in effect reorder the
usable part of the list. Assuming this poses no problem for your
intended usage, the speed improvement will be an order of magnitude in
complexity in that each invocation will be O(1).
So here is the specific code. We will begin with a list that has a 1
explicitly prepended as the counter element.
SetAttributes[randomChooseElem, HoldFirst]
randomChooseElem[list_] := Module[
{pos, n=list[[1]]+1},
pos = Random[Integer, {n,Length[list]}];
list[[1]] = n;
list[[{n,pos}]] = list[[{pos,n}]];
list[[n]]
]
list = Prepend[Range[10^5],1];
In[15]:= Timing[Do[randomChooseElem[list],{10^4}]]
Out[15]= {0.352022, Null}
Let's check the first few elements.
In[16]:= Take[list,10]
Out[16]= {10001, 70005, 35656, 87986, 65014, 81012,
46618, 24385, 13312, 24467}
We see that teh counter is now at 10^4+1, and the first few chosen were
70005, 35656, etc.
Let's look at the last several elements.
In[19]:= Take[list,-10]
Out[19]= {99991, 99992, 8775, 99994, 1917, 9029,
99997, 99998, 99999, 100000}
As expected, most retain their original values but a few (e.g. 999923)
were among the 10^4 selections we made.
Daniel Lichtblau
Wolfram Research
Prev by Date:
**Re: ListDimension function**
Next by Date:
**Re: ListDimension function**
Previous by thread:
**Re: Call-by-reference from inside a function**
Next by thread:
**Re: Call-by-reference from inside a function**
| |