[Tutor] A shorter way to initialize a list?
Steven D'Aprano
steve at pearwood.info
Wed Dec 14 00:25:04 CET 2011
Kaixi Luo wrote:
> Hello,
>
> I want to create a list of lists of lists (listB) from a list of lists
> (listA). Below there's a snippet of my code:
>
> list1 = [[] for i in range(9)]
>
> # some code here...
>
> listA = [[] for i in range(3)]
> count = 0
> for i in range(3):
> for j in range(3):
> listB[i].append(listA[count])
> count+=1
I'm afraid that I don't know what you are trying to do here, because your
snippet doesn't work. So I have to *guess* what you're actually trying to do.
My guess is that you have a list of lists, and you want to copy it. Here's one
way, using a slice over the entire list.
>>> listA = [[1], [1,2], [1,2,3], [1,2,3,4], [1,2,3,4,5]]
>>> listB = listA[:] # like listA[0:5]
listA and listB are now independent lists, but the sublists are shared:
>>> listA.append(None) # modify listA, and listB is unchanged
>>> listB
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
>>> listA[0].append(None) # but modify a shared sublist
>>> listB # and listB sees the same change
[[1, None], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
If that's not the behaviour you want, you need to make copies of the inner
lists too:
>>> listA = [[1], [1,2], [1,2,3], [1,2,3,4], [1,2,3,4,5]]
>>> listB = [inner[:] for inner in listA]
>>>
>>> listA.append(None)
>>> listA[0].append(None)
>>> listB
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
That's easy enough when listA is a nested list of lists one level deep, but if
it contains a mix of lists and scalars, or multiple levels, you should use the
copy module to do the copying:
import copy
listB = copy.deepcopy(listA)
How do you create a two-dimensional array? The basic technique is with a
nested list comprehension:
>>> [[2**j for j in range(4)] for i in range(i)]
[[1, 2, 4, 8], [1, 2, 4, 8], [1, 2, 4, 8], [1, 2, 4, 8], [1, 2, 4, 8]]
This is equivalent to:
listA = []
for i in range(5):
listB = []
for j in range(4):
listB.append(2**j)
listA.append(listB)
only slightly shorter :)
If all you need is a two-dimension array of numbers 0...n, use the range()
built-in to generate the inner lists:
>>> [list(range(4)) for i in range(5)]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
The call to list() is needed in Python 3, where range() returns a lazy
iterator; in Python 2, it returns a list and you don't need to call list()
(but it doesn't hurt if you do).
--
Steven
More information about the Tutor
mailing list