MathGroup Archive 2000

[Date Index] [Thread Index] [Author Index]

Search the Archive

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.


  • Prev by Date: Arbitrary precision addition
  • Next by Date: Re: Why is Mathematica so slow ?
  • Previous by thread: Re: Summary: List element manipulation
  • Next by thread: Re: winding number