# Newbiequestion about lists and arrays....

Discussion in 'Python' started by Michael, Sep 6, 2003.

1. ### MichaelGuest

Hi pythonians! (or whatever you call yourselfs...)

I would like to use an multidimensional matrix (3D or more) with
numbers (int:s and float:s). Could i use lists or arrays? How can i
retrieve a single element out of a list thats already in an other list
thats already in an other list (and so on...)

An example...

c=[1]*3
for y in range(3):
for x in range(3):

c[x]=[1,2,3]
p[y]=c

p[1][1][1]=888
print p[1][1][1]
print p

for this code example, how do i assign 888 to only one element (for
example, the element in the middle) in the matrix and not to the three
elements shown below?

>>>

888
[[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]]]
>>>

Why does:

p[0][1][1]=888

and

p[1][1][1]=888

print out the same result?

/Michael

Michael, Sep 6, 2003

2. ### Erik Max FrancisGuest

Michael wrote:

> I would like to use an multidimensional matrix (3D or more) with
> numbers (int:s and float:s). Could i use lists or arrays? How can i
> retrieve a single element out of a list thats already in an other list
> thats already in an other list (and so on...)

It's because Python doesn't have copy semantics. You're building a list
of lists of lists, some of whose elements are references to the same
list.

To ensure that these lists are all distinct objects, and thus giving you
the expected behavior, don't use references to previous objects; create

>>> c = []
>>> for x in range(3):

.... xs = []
.... for y in range(3):
.... ys = []
.... for z in range(3):
.... ys.append([1, 2, 3])
.... xs.append(ys)
.... c.append(xs)
....
>>> c

[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]],
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]]
>>> c[1][1][1] = 888
>>> c

[[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], 888, [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]], [[[1,
2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2,
3], [1, 2, 3], [1, 2, 3]]]]

There are other ways to do the job, of course, involing say list
comprehensions.

--
Erik Max Francis && && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \ You're wasting time / Asking what if / You linger on too long
\__/ Chante Moore

Erik Max Francis, Sep 6, 2003

3. ### Sean RossGuest

"Michael" <> wrote in message
news:...

[snip]

> c=[1]*3
> for y in range(3):
> for x in range(3):
>
> c[x]=[1,2,3]
> p[y]=c
>
> p[1][1][1]=888
> print p[1][1][1]
> print p

[snip]

> Why does:
>
> p[0][1][1]=888
>
> and
>
> p[1][1][1]=888
>
> print out the same result?

Hi.
The problem is with "p[y] = c". This line binds p[y] to whatever c is bound
to.

c
\
[[1,2,3], [1,2,3], [1,2,3]]
/
p[y]

But, then, you've done this for all p[y], 0<=y<3, so

c
\
[[1,2,3], [1,2,3], [1,2,3]]
/ | |
p[0] p[1] p[2]

Now you modify p[1][1][1]:

p[1][1][1] = 888

with this result:

c
\
[[1,2,3], [1,888,3], [1,2,3]]
/ | |
p[0] p[1] p[2]

Thus, p, which is [p[0], p[1], p[2]], looks like

[[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]]]

Which is not what you wanted. To avoid this, you need only change

p[y] = c

to

p[y] = c[:]

c[:] creates a copy of whatever c was bound to. p[y] is then bound to that
copy.

c
\
[[1,2,3], [1,2,3], [1,2,3]] # original

[[1,2,3], [1,2,3], [1,2,3]] # copy (c[:])
/
p[y]

This happens for each y, 0<=y<3, so

c
\
[[1,2,3], [1,2,3], [1,2,3]] # original

[[1,2,3], [1,2,3], [1,2,3]] # copy (c[:])
/
p[0]

[[1,2,3], [1,2,3], [1,2,3]] # copy (c[:])
/
p[1]

[[1,2,3], [1,2,3], [1,2,3]] # copy (c[:])
/
p[2]

Now, when you do

p[1][1][1] = 888

The result is

c
\
[[1,2,3], [1,2,3], [1,2,3]]

[[1,2,3], [1,2,3], [1,2,3]]
/
p[0]

[[1,2,3], [1,888,3], [1,2,3]]
/
p[1]

[[1,2,3], [1,2,3], [1,2,3]]
/
p[2]

And, thus, p, which is [p[0], p[1], p[2]], looks like:

[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]

Which is what you were looking for.

Or, you could just build 'p' using a list comprehension:

>>> from pprint import pprint as puts
>>> p = [[[1,2,3] for y in range(3)] for x in range(3)]
>>> p[1][1][1] = 888
>>> puts(p)

[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 888, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]

Which is also what you were looking for.

HTH
Sean

Sean Ross, Sep 6, 2003