How to initialize a two-dimensional array in Python?
A pattern that often came up in Python was
bar = []
for item in some_iterable:
bar.append(SOME EXPRESSION)
which helped motivate the introduction of list comprehensions, which convert that snippet to
bar = [SOME_EXPRESSION for item in some_iterable]
which is shorter and sometimes clearer. Usually, you get in the habit of recognizing these and often replacing loops with comprehensions.
Your code follows this pattern twice
twod_list = [] \
for i in range (0, 10): \
new = [] \ can be replaced } this too
for j in range (0, 10): } with a list /
new.append(foo) / comprehension /
twod_list.append(new) /
Don't use [[v]*n]*n
, it is a trap!
>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
but
t = [ [0]*3 for i in range(3)]
works great.
You can use a list comprehension:
x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)
This way is faster than the nested list comprehensions
[x[:] for x in [[foo] * 10] * 10] # for immutable foo!
Here are some python3 timings, for small and large lists
$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop
$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop
$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop
$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop
Explanation:
[[foo]*10]*10
creates a list of the same object repeated 10 times. You can't just use this, because modifying one element will modify that same element in each row!
x[:]
is equivalent to list(X)
but is a bit more efficient since it avoids the name lookup. Either way, it creates a shallow copy of each row, so now all the elements are independent.
All the elements are the same foo
object though, so if foo
is mutable, you can't use this scheme., you'd have to use
import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]
or assuming a class (or function) Foo
that returns foo
s
[[Foo() for x in range(10)] for y in range(10)]