List of lists with incremented elements - python

I've made some generic example of my problem.
I have something like this:
n = 2
test = [[[0,0] for j in range(1)] for k in range(n)]
print(test)
And I get the following output:
[[[0, 0]], [[0, 0]]]
But what I want - as output - is something like that:
[[[0, 0]], [[0, 0],[0, 0]]]
And for n = 3, the output must be:
[[[0, 0]], [[0, 0],[0, 0]], [[0,0],[0,0],[0,0]]]

You can do it by specifying the start argument of range:
[[[0,0] for _ in range(k)] for k in range(1, n+1)]
Output (for n=3):
[[[0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0], [0, 0]]]

Related

Python 2-D ARRAY CONFUSION

I don't understand why the entire 2D is getting populated while I am trying ton access only the diagonal elements:
a = [[0]*3]*3
print("INIT ARRAY: ", a)
for i in range(3):
a[i][i] = 1
print("FINAL ARRAY:", a)
Answer :
INIT ARRAY: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
FINAL ARRAY: [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
REASON
This is happening because all three arrays (or list) are stored in the same memory (RAM) location when you multiply them.
You can find the memory location of the object in python by using
id(object_name)
Now try this code to understand the reason.
a = [[0]*3]*3
print("INIT ARRAY: ", a)
print(id(a[0][0]))
print(id(a[1][0]))
print(id(a[2][0]))
OUTPUT
INIT ARRAY: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
140394015555792 #all three lists have same memory location.
140394015555792
140394015555792
That is why when you are modifying only diagonal elements other elements also get modified.
SOLUTION
a = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] # This list elements have memory location
print("Initial ARRAY", a)
for i in range(3):
a[i][i] = 1
print("Final ARRAY", a)
OUTPUT
Initial ARRAY [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Final ARRAY [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
SOLUTION
a = []
# Method you can use to generate array with different memory locations.
for i in range(3):
a.append([])
for j in range(3):
a[i].append(0)
print("INIT ARRAY: ", a)
for i in range(3):
a[i][i] = 1
print("FINAL ARRAY:", a)
OUTPUT
INIT ARRAY: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
FINAL ARRAY: [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

Python replacing all list elements instead of the indexed list element in for loop

I want to replace the kth element of the kth element of the list.
E.g.,
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]
to
[[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
BUT python does not seem to want to do that and instead is replacing each value for each element.
I run this:
# Triangle Vertices
V = [[0, 1], [-1, 0], [1, 0]]
# Triangles (indices of V in clockwise direction)
T = [[1, 0, 2]]
# Creating sub-triangles
bary_point = [0, 0.5]
v_list = []
for t in T:
print(t)
for k in range(3):
v_list.append(V)
v_list[k][k] = bary_point # <-- This line
print('v_list: ')
print(v_list)
and it produces this:
v_list:
[[[0, 0.5], [0, 0.5], [0, 0.5]],
[[0, 0.5], [0, 0.5], [0, 0.5]],
[[0, 0.5], [0, 0.5], [0, 0.5]]]
but I want this:
v_list:
[[[0, 0.5], [-1, 0], [1, 0]],
[[0, 1], [0, 0.5], [1, 0]],
[[0, 1], [-1, 0], [0, 0.5]]]
Am I doing something wrong? I am on Python 3.10.0
Thank you.
EDIT Solution:
Change
v_list.append(V)
to
v_list.append(V.copy())
Thank you!
You are appending the same reference to the list V, and when you change v_list[k][k] you are changing V, one solution would be to append a copy of the list, by using V.copy() as argument to append.

Unexpected behaviour in list value change

I defined this function:
def newMap(dim, n):
tc = [0 for i in range(n)]
return [[tc for _ in range(dim)] for _ in range(dim)]
Which creates a list of lists of zeroes. For example
m = newMap(2,2)
print(m)
returns
[[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
I want to change one os the zeroes to obtain [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] and tried doing so by
m[0][0][0] = 1
which, unexpectedly returns [[[1, 0], [1, 0]], [[1, 0], [1, 0]]] instead of [[[1, 0], [0, 0]], [[0, 0], [0, 0]]].
However, if I defined a = [[[0, 0], [0, 0]], [[0, 0], [0, 0]]], and then do
a[0][0][0] = 1
print(a)
it returns [[[1, 0], [0, 0]], [[0, 0], [0, 0]]], which is what I want.
Why does this happen? Shouldn't the two definitions be equivalent? How can I prevent it from happening in the first case?
Use tc.copy() this should fix it, i tried it and it works:
def newMap(dim, n):
tc = [0 for i in range(n)]
return [[tc.copy() for _ in range(dim)] for _ in range(dim)]
a = newMap(2,2)
a
#[[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
a[0][0][0] = 1
#[[[1, 0], [0, 0]], [[0, 0], [0, 0]]]

How do I create many matrices inside a loop statement with python?

I want to create for example n matrices like:
m1 = [[0,0],[0,0]]
m2 = [[0,0],[0,0]]
.
.
mn = [[0,0],[0,0]]
I think that will work for you
res = [[[0 for item3 in range(2)] for item2 in range(2)] for item1 in range(10)]
print res
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]],
[[0, 0], [0, 0]],
[[0, 0], [0, 0]],
[[0, 0], [0, 0]],
[[0, 0], [0, 0]]
]
Basically 10(your n value) arrays with 2x2 lists of zeros.

Python 2.7 creating a multidimensional list

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.

Categories