[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