Re: Summary: List element manipulation

*To*: mathgroup at smc.vnet.net*Subject*: [mg25780] Re: Summary: List element manipulation*From*: Robert Knapp <rknapp at wolfram.com>*Date*: Wed, 25 Oct 2000 03:53:41 -0400 (EDT)*Organization*: Wolfram Research, Inc.*References*: <8r19qf$hvt@smc.vnet.net> <8r6oij$1c@smc.vnet.net>*Sender*: owner-wri-mathgroup at wolfram.com

Martin Rommel wrote: > > Thanks to the many helpful people that replied with their insight. > The straightforward fix to my problematic > > > MapAt[Decrement, Range[116, 166, 8], -1] > > > > Decrement::"rvalue": "164 is not a variable with a value, so its value > > cannot be changed." > > is using a function # - 1& instead of Decrement (which is not a mathematical > function but instead listed under programming assignments in the help > browser) > > MapAt[# - 1&, Range[116, 166, 8], -1] > > This was suggested by the news group veterans David Park, Andrzej Kozlowski, > Hartmut Wolf and Allan Hayes. > > Matt Johnson suggested an alternative using a rule (it is always interesting > to see things done differently) > > Range[116, 166, 8] /. {h___, t_} -> {h, t - 1} > > Special thanks to Andrzej Kozlowski for additonal explainations but the most > in depth coverage came from my compatriot Hartmut Wolf. > > With hindsight I don't understand why I was so fixated on employing > Decrement. > Actually, depending on what you want to do, using Decrement is a very good idea here. If you want to make a copy of the list with the last element one less than in the previous copy, the above methods are just fine. However, if you can modify the last element in place, then Decrement is the way to go: list = Range[116,166, 8]; (* Decrement the last element -- referred to by the -1 Part *) Decrement[list[[-1]]] If you are decrementing in a loop, the above suggested options are very expensive because you end up doing a lot of copying. Here is an example for a larger input: In[1]:= list = Range[10000]; In[2]:= Timing[ newlist = list; While[newlist[[-1]] > 1, newlist = MapAt[# - 1 &, newlist, -1]]; newlist[[-1]]] Out[2]= {30.76 Second, 1} In[3]:= Timing[ newlist = list; While[newlist[[-1]] > 1, newlist = newlist /. {h___, t_} -> {h, t - 1}]; newlist[[-1]]] Out[3]= {37.34 Second, 1} adam_smith at my-deja.com wrote: > > I thought that you might find this of interest. I decided to try a > different method using ReplacePart[]. As shown below it can run quite > a bit faster for large lists. IMHO It also seems a little clearer to > follow, although not as compact and elegant as MapAt[]. Note, the > timing differences are insignificant for vectors 2000 elements or less. > (I am running Version 4.0.1.0 under Windows NT SP5 I think on a 333 MHz > Pentium II with 196 MB memory) > In[4]:= Timing[ newlist = list; While[newlist[[-1]] > 1, newlist = ReplacePart[newlist, newlist[[-1]] - 1, -1]]; newlist[[-1]]] Out[4]= {1.61 Second, 1} Mr. Smith is quite right. ReplacePart is much faster. The reason is that with ReplacePart, Mathematica is able to use packed arrays. However, ReplacePart is still making copies, so In[5]:= Timing[ newlist = list; While[Decrement[newlist[[-1]]] > 1]; newlist[[-1]]] Out[5]= {0.23 Second, 0} is faster yet. The difference will increase as the list size increases.