I had to thought about it a little bit, but then I came up with this solution: (7 lines without import)
# helper
def cl(n, func):
# return a lambda, that returns a list, where func(tion) is called
return (lambda: [func() for _ in range(n)])
def matrix(base, *ns):
# the grid lambda (at the start it returns the base-element)
grid = lambda: base
# traverse reversed, to handle the midmost values first
for n in reversed(ns):
# assign a new lambda with the last grid within (and call it)
grid = cl(n, grid)
return grid() # call the full grid (but the matrix calls you ^^)
The tests give the following results:
>>> from pprint import pprint as pp
>>>
>>> matrix(None, 2,3)
[[None, None, None], [None, None, None]]
>>>
>>> matrix(None, 4,3)
[[None, None, None], [None, None, None], [None, None, None], [None, None, None]]
>>>
>>> x = matrix(None, 3,5,2)
>>> pp(x)
[[[None, None], [None, None], [None, None], [None, None], [None, None]],
[[None, None], [None, None], [None, None], [None, None], [None, None]],
[[None, None], [None, None], [None, None], [None, None], [None, None]]]
>>> x[1][3][0] = "test"
>>> pp(x)
[[[None, None], [None, None], [None, None], [None, None], [None, None]],
[[None, None], [None, None], [None, None], ['test', None], [None, None]],
[[None, None], [None, None], [None, None], [None, None], [None, None]]]
Another solution, which has the advantage of using the "[[[0]]*5]*5"-syntax:
def uniq(base, l):
# function used to replace all values with the base
nl = []
for i in l:
if type(i) is list:
nl.append(uniq(base, i)) # recursion for deep lists
else:
nl.append(base)
return nl
Test:
# first arg is the base, the 0 inside the [] is just a dummy
# (for what None is the best choice usually)
>>> x = uniq(0, [[[0]]*5]*5)
>>> x[0][3][0] = 5
>>> pp(x)
[[[0], [0], [0], [5], [0]],
[[0], [0], [0], [0], [0]],
[[0], [0], [0], [0], [0]],
[[0], [0], [0], [0], [0]],
[[0], [0], [0], [0], [0]]]
btw. the numpy library has a np.zeros(s)
-function, where s
is a shape like (3,4,5)
>>> s = (2,2)
>>> np.zeros(s)
array([[ 0., 0.],
[ 0., 0.]])
Finally a performance test:
# functions are already defined ...
import timeit
>>> # Alex Martelli's Code
>>> t1 = timeit.Timer( lambda: multi_dimension_list(None, 3,4,5) )
>>> # the two mentioned above
>>> t2 = timeit.Timer( lambda: matrix(None, 3,4,5) )
>>> t3 = timeit.Timer( lambda: uniq(None, [[[None]*5]*4]*3) )
>>>
>>> t1.timeit(10000)
2.1910018920898438
>>> t2.timeit(10000)
0.44953203201293945
>>> t3.timeit(10000)
0.48807907104492188
I found it really interesting to discover this problem. So, thanks for the question :)