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
- References:
- Call-by-reference from inside a function
- From: "zac" <replicatorzed@gmail.com>
- Call-by-reference from inside a function