In Python I want an intuitive way to create a 3 dimensional list.
I want an (n by n) list. So for n = 4 it should be:
x = [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]]
I've tried using:
y = [n*[n*[]]]
y = [[[]]* n for i in range(n)]
Which both appear to be creating copies of a reference.
I've also tried naive application of the list builder with little success:
y = [[[]* n for i in range(n)]* n for i in range(n)]
y = [[[]* n for i in range(1)]* n for i in range(n)]
I've also tried building up the array iteratively using loops, with no success. I also tried this:
y = []
for i in range(0,n):
y.append([[]*n for i in range(n)])
Is there an easier or more intuitive way of doing this?
I think your list comprehension versions were very close to working. You don't need to do any list multiplication (which doesn't work with empty lists anyway). Here's a working version:
>>> y = [[[] for i in range(n)] for i in range(n)]
>>> print y
[[[], [], [], []], [[], [], [], []], [[], [], [], []], [[], [], [], []]]
looks like the most easiest way is as follows:
def create_empty_array_of_shape(shape):
if shape: return [create_empty_array_of_shape(shape[1:]) for i in xrange(shape[0])]
it's work for me
i found this:
Matrix = [[0 for x in xrange(5)] for x in xrange(5)]
You can now add items to the list:
Matrix[0][0] = 1
Matrix[4][0] = 5
print Matrix[0][0] # prints 1
print Matrix[4][0] # prints 5
from here: How to define two-dimensional array in python
A very simple and elegant way is:
a = [([0] * 5) for i in range(5)]
a
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
In Python I made a little factory method to create a list of variable dimensions and variable sizes on each of those dimensions:
def create_n_dimensional_matrix(self, n):
dimensions = len(n)
if (dimensions == 1):
return [0 for i in range(n[0])]
if (dimensions == 2):
return [[0 for i in range(n[0])] for j in range(n[1])]
if (dimensions == 3):
return [[[0 for i in range(n[0])] for j in range(n[1])] for k in range(n[2])]
if (dimensions == 4):
return [[[[0 for i in range(n[0])] for j in range(n[1])] for k in range(n[2])] for l in range(n[3])]
run it like this:
print(str(k.create_n_dimensional_matrix([2,3])))
print(str(k.create_n_dimensional_matrix([3,2])))
print(str(k.create_n_dimensional_matrix([1,2,3])))
print(str(k.create_n_dimensional_matrix([3,2,1])))
print(str(k.create_n_dimensional_matrix([2,3,4,5])))
print(str(k.create_n_dimensional_matrix([5,4,3,2])))
Which prints:
The two dimensional lists (2x3), (3x2)
The three dimensional lists (1x2x3),(3x2x1)
The four dimensional lists (2x3x4x5),(5x4x3x2)
[[0, 0], [0, 0], [0, 0]]
[[0, 0, 0], [0, 0, 0]]
[[[0], [0]], [[0], [0]], [[0], [0]]]
[[[0, 0, 0], [0, 0, 0]]]
[[[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]], [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]], [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]], [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]], [[[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]]
[[[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]], [[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]]
How about this:
class MultiDimList(object):
def __init__(self, shape):
self.shape = shape
self.L = self._createMultiDimList(shape)
def get(self, ind):
if(len(ind) != len(self.shape)): raise IndexError()
return self._get(self.L, ind)
def set(self, ind, val):
if(len(ind) != len(self.shape)): raise IndexError()
return self._set(self.L, ind, val)
def _get(self, L, ind):
return self._get(L[ind[0]], ind[1:]) if len(ind) > 1 else L[ind[0]]
def _set(self, L, ind, val):
if(len(ind) > 1):
self._set(L[ind[0]], ind[1:], val)
else:
L[ind[0]] = val
def _createMultiDimList(self, shape):
return [self._createMultiDimList(shape[1:]) if len(shape) > 1 else None for _ in range(shape[0])]
def __repr__(self):
return repr(self.L)
You can then use it as follows
L = MultiDimList((3,4,5)) # creates a 3x4x5 list
L.set((0,0,0), 1)
L.get((0,0,0))
import copy
dimensions = 2, 3, 4
z = 0
genList = lambda size,value: [copy.deepcopy(value) for i in range(size)]
for i in dimensions: z = genList(i, z)
I am amazed no one tried to devise a generic way to do it.
See my answer here: https://stackoverflow.com/a/33460217/5256940
import copy
def ndlist(init, *args): # python 2 doesn't have kwarg after *args
dp = init
for x in reversed(args):
dp = [copy.deepcopy(dp) for _ in xrange(x)] # Python 2 xrange
return dp
l = ndlist(0, 1, 2, 3, 4) # 4 dimensional list initialized with 0's
l[0][1][2][3] = 1
Edit: Built on user2114402's answer: added default value parameter
def ndlist(s, v):
return [ndlist(s[1:], v) for i in xrange(s[0])] if s else v
Here's one that will give you an N dimensional "matrix" filled up with copies of a copiable object.
Edit: This is a slight modification of pterodragon's original answer, which I much prefer to user2114402's less readable answer. In fact, outside of a doc-string the only difference from pterodragon's solution is that I explicitly use a list of dimension sizes, rather than have the user pass them as arguments.
import copy
def instantiate_mdl(dim_maxes, base=0):
""" Instantiate multi-dimensional list, that is a list of list of list ...
Arguments:
dim_maxes (list[int]): a list of dimension sizes, for example
[2, 4] represents a matrix (represented by lists) of 2 rows and
4 columns.
base (object): an optional argument indicating the object copies
of which will reside at the lowest level in the datastructure.
Returns:
base (list[base]): a multi-dimensional list of lists structure,
which is filled with clones of the base parameter.
"""
for dim_max in reversed(dim_maxes):
base = [copy.deepcopy(base) for i in range(dim_max)]
return base
data = instantiate_mdl([3, 5])
data[0][0] = 99999
data[1][1] = 88888
data[2][4] = 77777
for r in data:
print(r)
>>> # Output
>>> [99999, 0, 0, 0, 0]
>>> [0, 88888, 0, 0, 0]
>>> [0, 0, 0, 0, 77777]
Here is a losution that works for any number of dimention :
def multi_dimensional_list(dimensions, filling=None):
if len(dimensions) == 1:
return [filling] * dimensions[0]
else:
return [
multi_dimensional_list(dimensions[1:], filling)
for _ in range(dimensions[0])
]
print(multi_dimensional_list([2, 3, 4], 0))
"""
output :
[
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
]
"""
Here is a more generic way of doing it.
def ndlist(shape, dtype=list):
t = '%s for v%d in xrange(shape[%d])'
cmd = [t % ('%s', i + 1, i) for i in xrange(len(shape))]
cmd[-1] = cmd[-1] % str(dtype())
for i in range(len(cmd) - 1)[::-1]:
cmd[i] = cmd[i] % ('[' + cmd[i + 1] + ']')
return eval('[' + cmd[0] + ']')
list_4d = ndlist((2, 3, 4))
list_3d_int = ndlist((2, 3, 4), dtype=int)
print list_4d
print list_3d_int
Result:
[[[[], [], [], []], [[], [], [], []], [[], [], [], []]], [[[], [], [], []], [[], [], [], []], [[], [], [], []]]]
[[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]]
You can also build a 2D list with different length rows using the append method.
e.g.
sf_gcov_cell = []
sf_gcov_cell.append(['r1_c1', 'r2_c2_', 'r3_c3__', 'r4_c4'])
sf_gcov_cell.append(['r2_c1', 'r2_c2'])
sf_gcov_cell.append(['r3_c1', 'r3_c2___', 'r3_c3_'])
print(sf_gcov_cell)
Result:
[['r1_c1', 'r2_c2_', 'r3_c3__', 'r4_c4'], ['r2_c1', 'r2_c2'], ['r3_c1', 'r3_c2___', 'r3_c3_']]
Just use a simple recursive function that continuously appends new arrays to the initialized arrays within itself.
# Counts the maximum amount of dimensions in an array
def dcounter(array: list, total = 1):
for arr in array:
return dcounter(arr, total + 1)
return total
# Create array with specified amount of dimensions
def nd_array(dimensions = 1, array = list(), i = 0):
if dimensions > 1:
array.append([])
nd_array(dimensions - 1, array[i])
return array
# Create a 5D array
array = nd_array(5)
print(array) # => "[[[[[]]]]]"
# Get the maximum amount of dimensions in the array
amount = dcounter(array)
print(amount) # => "5"
If you wanted to specify the size of each dimension, the amount of arrays within each dimension, then you could modify nd_array into doing so.