Q: efficient in-place list element replacement?
- To: mathgroup at smc.vnet.net
- Subject: [mg21091] Q: efficient in-place list element replacement?
- From: simon shannon <sshannon at taz.dra.hmg.gb>
- Date: Sun, 12 Dec 1999 23:51:59 -0500 (EST)
- Organization: dera
- Sender: owner-wri-mathgroup at wolfram.com
dear Mathematica wizards,
how can i do efficient in-place list element replacement?
i have a small nugget of 'unexpected behaviour' that took me
hours to track down. vastly simplified, the problem is this:
a = {4,5,6,7,67,89}
i know i want to replace the third element with
some new elements:
p = 3;
a[[p]] = Sequence @@ {"a","b","c"};
i look at the result, and a is apparently
{4, 5, a, b, c, 7, 67, 89}
Length[a] returns 8; still looks good...
a[[4]] returns "b"; still looks good...
now we change the 7th element of our list
a[[7]] = Pi;
...and we get the blue error message
Set::partw: Part 7 of {4, 5, Sequence[a, b, c], 7, 67, 89} does not
exist.
so, my first questions are:
(1) why is the Sequence head still there?
(2) why was it invisible to Part---ie a[[4]] was happy
to give the result "b"
(3) why was it also invisible to Length?
(4) why does even FullForm[a] and InputForm[a]
not acknowledge the presence of the Sequence head?
what i am trying to avoid is copying the list a. for my real
problem a is a large complicated list with lots of substructure;
since i know exactly which bit i want to change, i thought
it would just be a matter of updating a few pointers (i was a
lisp programmer many moons ago).
a friend suggests that i use Flatten, and rely on the clever
internal routines that spot when there is duplication;
but look at the following:
data = Table[Random[], {100000}];
{MemoryInUse[], MaxMemoryUsed[]}/1024//Round
data[[654]] = {0.3,0.4,0.5};
{MemoryInUse[], MaxMemoryUsed[]}/1024//Round
data = Flatten[data,1];
{MemoryInUse[], MaxMemoryUsed[]}/1024//Round
gives the following output:
{1926, 1934}
{3897, 3904}
{3897, 4776}
there is a big increase in memory use at the element replacement,
sort of indicating that the data was copied then; true enough,
there is not much of an increase after the Flatten[], so maybe
it is clever.
to quote form dave wagner's book on "power programmin with Mathematica the
kernel"
it says on page 305 with a "be alert" icon:
"the problem with building up lists an element at a time is that Mathematica
lists
are implemented as arrays. the advantage of this implementation is that
a list can be randomly indexed in time that is independent of the length
of a list...."
i just tried it, and it is true: so things aren't as easy as
maniplulating
a few pointers in lisp. i wasn't a lert before, but i am one now.
so, are there any efficient (ie non-copying) ways of modifying an
existing
list?
any comments welcome
- simon shannon