Re: Re: Re: Set in Scan
- To: mathgroup at smc.vnet.net
- Subject: [mg22055] Re: [mg22008] Re: [mg21900] Re: [mg21856] Set in Scan
- From: "Tomas Garza" <tgarza at mail.internet.com.mx>
- Date: Fri, 11 Feb 2000 02:38:39 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
Dear Hartmut, Thanks a lot for your painstakingly detailed explanation. It certainly was very helpful in understanding what goes on inside Scan. However, I'm still at a loss concerning the problem of a very long list of fixed-size (not necessarily too long, maybe less than 20) lists where the assignment may be something which depends on the value of the element to be replaced, e.g., Function[sym,If[sym[[3]] < 0.5, "-XXX-","-YYY-"]], so that it is not possible to use allv[[All,3]] = k since here k would have to be the same for each element of allv. But I can't use Scan[Function[sym, (#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])&@ Unevaluated[sym], {HoldFirst}], Unevaluated[{v1, v2, v3}]] or Scan[(#[[3]] = new) &, Unevaluated /@ Hold[v1, v2, v3]] as Allan Hayes suggests, since I would have to write explicitly the full list {v1, v2,..., vN}, which is out of the question for very large N (between 10,000 and 20,000). So far I have been using a ReplaceAll approach which is unbelievably slow. I'm sure the Scan approach is much faster, but... I would be very grateful for any hint. Tomas Garza Mexico City ----------------------------------------------------------- > Tomas Garza schrieb: > > > > It looks as if the suggested approach of Hartmut Wolf's - as > well as Jens > > Peer Kuska's - to this problem works fine and is extremely efficient. > > However, suppose that instead of having a few possibly very > long lists {v1, > > v2, v3} one has a large number N - perhaps of the order of tens of > > thousands - of such lists, which need not be too long. The > procedure would > > have to be modified > > In fact! This is a different problem, and it's for this one indeed, that > the second proposal I made -- as Allan Hayes did -- comes to full > strength. Perhaps you might go back in this thread to Allan's answer, to > see that the elements of the compound object, the lists v<i> even need > not be of same length, *however* all v<i> must be long enough to at > least include the replace position, else nothing will be replaced at > all. > > To do the replacement only in those sublists being long enough would > again consitute another problem. > > > ... in order to use some symbol like allv = > {v1, v2,..., vN} > > in Scan, instead of writing the complete list with all > individual v's, as > > used by Hartmut and Jens: > > > > Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}], > > Unevaluated[{v1, v2, v3}]] > > > > However, if I write > > > > Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}], > > Unevaluated[allv]] > > > > nothing happens. > > It can't, because Unevaluated reaches to Scan (i.e. to it's procedural > machinery) the unevaluated symbol allv, and if you scan a symbol nothing > happens. Scan doesn't even look at the Head of an expression, even be it > Hold -- as Allan noticed -- instead it feeds on the elements, yet there > are none in this case. It's only that > > OwnValues[allv] > > {HoldPattern[allv] :> > {{0.308624, 0.0113816, 0.452114, 0.100156}, > {0.368705, 0.44588, 0.878839, 0.736246}, > {0.71764, 0.18652, 0.667573, 0.338795}}} > > has such elements. > > > ... And the second suggestion by Hartmut is > unusable in case > > the assignment may be something which depends on the value of > the element to > > be replaced, e.g. Function[sym,If[sym[[3]] < 0.5, "-XXX-","-YYY-"]]. > > > > Well again this is not quite the same problem, but there is a natural > extending solution: > > Scan[Function[sym, > sym[[3]] = If[sym[[3]] < 0.5, "-XXX-", "-YYY-"], {HoldFirst}], > Unevaluated[{v1, v2, v3}]] > > > {v1, v2, v3} > > {{0.308624, 0.0113816, "-XXX-", 0.100156}, > {0.368705, 0.44588, "-YYY-", 0.736246}, > {0.71764, 0.18652, "-YYY-", 0.338795}} > > > Any suggestions? > > > > More along the lines of this discussion you would like to try > > Scan[Function[sym, > (#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])&@ Unevaluated[sym], > {HoldFirst}], > Unevaluated[{v1, v2, v3}]] > > Or the somewhat more obfuscated > > Scan[Evaluate, > Scan[((#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])& > @Unevaluated[#])&, > Unevaluated /@ Unevaluated[{v1, v2, v3}]]] > > no Hold attributes in. This even works when you replace the outer Scan > (to get the replaced elements evaluated) by Map although the inner Scan > doesn't return anything. > I guess this is neither a bug nor any intended use (of Map), but a > consequence of the requirement that repeated Scans should be possible. > This example at least is an argument that they should! > > > When had I looked for a solution to the problem posed originally by > Johannes Ludsteck that ideom Unevaluated /@ Unevaluated[{v1,v1,v3}] came > up to my mind shortly after I had sent off my reply > > Scan[(#[[3]] = -the new value-)&, Unevaluated /@ Unevaluated[{v1, v2, > v3}]] > > ... only to then learn from Allan Hayes > > Scan[(#[[3]] = -the new value-)&, Unevaluated /@ Hold[v1, v2, v3]] > > > At the time of my reply I had no time for measurement and guessed the > time complexity to be O[constant]. > > Now I did some comparitative measurements, each with a new kernel, so > having the same memory and history conditions: > > > --------- > In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}]; > In[2]:= > Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}], > Unevaluated[{v1, v2, v3}]] // Timing > Out[2]= > {1.071 Second, Null} > > In[3]:= Take[#, 4] & /@ {v1, v2, v3} > Out[3]= > {{0.675382, 0.55102, "-XXX-", 0.633244}, {0.422611, 0.715315, "-XXX-", > 0.426188}, {0.011633, 0.223577, "-XXX-", 0.240954}} > > --------- > In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}]; > In[2]:= > Scan[Function[sym, sym[[3]] = "-YYY-"], > Unevaluated /@ Unevaluated[{v1, v2, v3}]] // Timing > Out[2]= > {1.062 Second, Null} > > In[3]:= Take[#, 4] & /@ {v1, v2, v3} > Out[3]= > {{0.974173, 0.96568, "-YYY-", 0.747727}, {0.910969, 0.312475, "-YYY-", > 0.34289}, {0.729062, 0.611829, "-YYY-", 0.437515}} > > --------- > In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}]; > In[2]:= > Scan[(#[[3]] = "-ZZZ-") &, Unevaluated /@ Hold[v1, v2, v3]] // Timing > Out[2]= > {1.062 Second, Null} > In[3]:= > Take[#, 4] & /@ {v1, v2, v3} > Out[3]= > {{0.921074, 0.870566, "-ZZZ-", 0.553795}, {0.198232, 0.688503, "-ZZZ-", > 0.372325}, {0.799497, 0.21537, "-ZZZ-", 0.0673068}} > > plus yet another variant > > In[1]:= Clear[f]; Attributes[f] = {HoldFirst}; > In[2]:= f[sym_] := (sym[[3]] = "-WWW-") > In[3]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}]; > In[4]:= > Scan[f, Hold[v1, v2, v3]] // Timing > Out[4]= > {1.032 Second, Null} > In[5]:= > Take[#, 4] & /@ {v1, v2, v3} > Out[5]= > {{0.422896, 0.178604, "-WWW-", 0.193691}, {0.184583, 0.524976, "-WWW-", > 0.370107}, {0.592243, 0.952171, "-WWW-", 0.79216}} > > All four perform the same and are O[x], when x is the length of the > lists! > > I admit, I don't understand that. The Question is: what did we measure? > The Performance of the functions? -- obviously not. The performance of > Scan (through a list of three elements)? -- probably not. Seems just to > be the time of accessing the 3rd element of a list. See > > In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}]; > In[2]:= > {v1[[3]], v2[[3]], v3[[3]]} // Timing > Out[2]= > {0. Second, {0.969595, 0.192005, 0.637547}} > In[3]:= > {v1[[3]] = "-UUU-", v2[[3]] = "-UUU-", v3[[3]] = "-UUU-"} // Timing > Out[3]= > {1.052 Second, {"-UUU-", "-UUU-", "-UUU-"}} > > So it's Set[Part[...],...] which is not O[constant]