Creating lists of lists in a pythonic way - list

I'm using a list of lists to store a matrix in python. I tried to initialise a 2x3 Zero matrix as follows.
mat=[[0]*2]*3
However, when I change the value of one of the items in the matrix, it changes the value of that entry in every row, since the id of each row in mat is the same. For example, after assigning
mat[0][0]=1
mat is [[1, 0], [1, 0], [1, 0]].
I know I can create the Zero matrix using a loop as follows,
mat=[[0]*2]
for i in range(1,3):
mat.append([0]*2)
but can anyone show me a more pythonic way?

Use a list comprehension:
>>> mat = [[0]*2 for x in xrange(3)]
>>> mat[0][0] = 1
>>> mat
[[1, 0], [0, 0], [0, 0]]
Or, as a function:
def matrix(rows, cols):
return [[0]*cols for x in xrange(rows)]

Try this:
>>> cols = 6
>>> rows = 3
>>> a = [[0]*cols for _ in [0]*rows]
>>> a
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
>>> a[0][3] = 2
>>> a
[[0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
This is also discussed in this answer:
>>> lst_2d = [[0] * 3 for i in xrange(3)]
>>> lst_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> lst_2d[0][0] = 5
>>> lst_2d
[[5, 0, 0], [0, 0, 0], [0, 0, 0]]

This one is faster than the accepted answer!
Using xrange(rows) instead of [0]*rows makes no difference.
>>> from itertools import repeat
>>> rows,cols = 3,6
>>> a=[x[:] for x in repeat([0]*cols,rows)]
A variation that doesn't use itertools and runs around the same speed
>>> a=[x[:] for x in [[0]*cols]*rows]
From ipython:
In [1]: from itertools import repeat
In [2]: rows=cols=10
In [3]: timeit a = [[0]*cols for _ in [0]*rows]
10000 loops, best of 3: 17.8 us per loop
In [4]: timeit a=[x[:] for x in repeat([0]*cols,rows)]
100000 loops, best of 3: 12.7 us per loop
In [5]: rows=cols=100
In [6]: timeit a = [[0]*cols for _ in [0]*rows]
1000 loops, best of 3: 368 us per loop
In [7]: timeit a=[x[:] for x in repeat([0]*cols,rows)]
1000 loops, best of 3: 311 us per loop

I use
mat = [[0 for col in range(3)] for row in range(2)]
although depending on what you do with the matrix after you create it, you might take a look at using a NumPy array.

This will work
col = 2
row = 3
[[0] * col for row in xrange(row)]

What about:
m, n = 2, 3
>>> A = [[0]*m for _ in range(n)]
>>> A
[[0, 0], [0, 0], [0, 0]]
>>> A[0][0] = 1
[[1, 0], [0, 0], [0, 0]]
Aka List comprehension; from the docs:
List comprehensions provide a concise way to create lists
without resorting to use of
map(), filter() and/or lambda.
The resulting list definition tends often to be clearer
than lists built using those constructs.

If the sizes involved are really only 2 and 3,
mat = [[0, 0], [0, 0], [0, 0]]
is easily best and hasn't been mentioned yet.

Is there anything itertools can't do? :)
>>> from itertools import repeat,izip
>>> rows=3
>>> cols=6
>>> A=map(list,izip(*[repeat(0,rows*cols)]*cols))
>>> A
[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]
>>> A[0][3] = 2
>>> A
[[0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]

Related

Python List - wierd behaviour

I was trying to solve the 3Sum problem in leetcode. but I observed python lists behaving different during the end of loop statement.
def threeSum(nums):
n=len(nums)
sum = {}
result = []
for i in range(n):
for j in range(i+1,n):
if i != j:
key = nums[i]+nums[j]
if key not in sum:
sum[key] = [nums[i],nums[j]]
for i in range(n):
if -nums[i] in sum:
temp = sum[-nums[i]]
temp.append(nums[i])
if(len(temp)<=3):
result.append(temp)
print(result)
print("at the end of loop")
print(result)
return "result printed"
nums = [-1,0,1,2,-1,-4]
print(threeSum(nums))
For the above function I got the output as
[[-1, 2, -1]]
[[-1, 2, -1], [-1, 1, 0]]
[[-1, 2, -1], [-1, 1, 0], [-1, 0, 1]]
[[-1, 2, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]]
at the end of loop
[[-1, 2, -1, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]]
result printed
From the output you can see that during the last iteration of the loop the result List variable contains the value [[-1, 2, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]] but when I print the same result at the end of the loop it is printed as [[-1, 2, -1, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2]] , the first element in List is changed.
How do you explain this? Am I missing something in the understanding of Python Lists?
P.S : Please ignore the solution of 3Sum problem, I already found another way to solve it, my question is regarding the Python List only
In Python, List is reference value. In your code, you refer to sum[1] 2 times. Both of 2 times return to the same List instance. That's why after the 2nd time, that List instance is appended 1 more number
This behavior is caused by two issues:
if(len(temp)<=3): will prevent printing the final result due to the length constraint
python lists are mutable and they can be modified from different places if the same object is referenced
In your case, at fourth iteration result[0] and temp will reference the same object. This is why result gets modified even it was not apparently touched. It was changed due to the change of temp variable. You can check this using additional prints to highlight current iteration, result and object ids.
for i in range(n):
print(i)
print(result)
if -nums[i] in sum:
temp = sum[-nums[i]]
temp.append(nums[i])
if(len(temp)<=3):
result.append(temp)
print(result)
print(id(result[0]))
print(id(temp))
print("at the end of loop")
print(result)
return "result printed"

Python: How to make values of a list in a list of lists zeros

I would like to make all the values in the first list inside the list of lists named "child_Before" below zero. The piece of code I wrote to accomplish this task is also shown below after the list:
child_Before = [[9, 12, 7, 3, 13, 14, 10, 5, 4, 11, 8, 6, 2],
[1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1],
[[1, 0], [1, 1]]]
for elem in range(len(child_Before[0])):
child_Before[0][elem] = 0
Below is the expected result:
child_After = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1],
[[1, 0], [1, 1]]]
However, I think there should be a more nibble way to accomplish this exercise. Hence, I welcome your help. Thank you in advance.
just to add a creative answer
import numpy as np
child_Before[0] = (np.array(child_Before[0])&0).tolist()
this is bad practice though since i'm using bitwise operasions in a senario where it is not intuitive, and i think there is a slight chance i'm making 2 loops xD on the bright site the & which is making all the zeros is O(1) time complexity
Just create a list of [0] with the same length as the original list.
# Answer to this question - make first list in the list to be all 0
child_Before[0] = [0] * len(child_Before[0])
As for you answer, I can correct it to make all the elements in the lists of this list to be zero.
# Make all elements 0
for child in range(len(child_Before)):
child_Before[child] = [0] * len(child_Before[child])
Use list comprehension:
child_after = [[i if n != 0 else 0 for i in j] for n, j in enumerate(child_Before)]

Gurobi and Python: how to query a dictionary using optimal variable solutions

I'm using Python and Gurobi and I'm having difficulty on how to optimal variable solutions to query a dictionary.
my_dict = {(i, j) : func(Z) for i in I for j in J}
my_dict results to be like this:
{(15687, 'B'): [[7, 0, 0, 0], [0, 7, 0, 0], [0, 0, 7, 0], [0, 0, 0, 7]],
...
(18906, 'C'): [[4, 0, 0, 3], [3, 0, 0, 3], [4, 0, 0, 0], [3, 0, 0, 0]}
Moreover I have a binary variable x[i, j, z] and an assignment constraint:
assignment = m.addConstrs((quicksum(x[i, j, z]
for z in range(len(my_dict[i, j]))) == 1
for i in I for j in J), "assignment")
Supposing I obtain as optimal solution variables
x[15687,'B',0] 1.000000
x[18906,'C',2] 1.000000
Is there a way to retrieve the sublist of my_dict corresponding to the "z" index?
(For instance, if my solution is x[18906,'C',2] 1.000000 then z = 2 and I want to obtain the sublist [4, 0, 0, 0])
Your code is not really a nice minimal example to work with, so it's hard to post valid code.
The general problem does not look that tough.
If your original dict looks like:
{(15687, 'B'): [[7, 0, 0, 0], [0, 7, 0, 0], [0, 0, 7, 0], [0, 0, 0, 7]],
...
(18906, 'C'): [[4, 0, 0, 3], [3, 0, 0, 3], [4, 0, 0, 0], [3, 0, 0, 0]}
and your solution is my_dict_opt, probably something like this should do (python3):
import numpy as np # easy fp-math comparison
sublists = []
for key, val in my_dict.items():
n_vars = len(val) # my assumption
for i in range(n_vars):
if np.isclose(my_dict_opt[key + tuple([i])].X, 1.0): # depends on your dict if .X is needed
sublists.append(my_dict[key][i])
Because of the dicts, the order of elements in sublists is not defined and this should only be a prototype as it's not really clear to me how those dicts are in use for you.

How to average sub arrays in Numpy using broadcasting?

If there is a numpy array that is a list of 2d arrays, is there more efficient way than calling the mean function twice?
z = np.array([[[0, 0, 0],
[10, 10, 10]],
[[0, 0, 0],
[5, 5, 5]],
[[0, 0, 0],
[2, 2, 2]]])
print(z.mean(axis=2).mean(axis=1))
>[ 5. 2.5 1. ]

Transforming a mapping matrix

I have a 2-dimensional array of ones and zeros called M where the g rows represent groups and the a columns represent articles. M maps groups and articles. If a given article "art" belongs to group "gr" then we have M[gr,art]=1; if not we have M[gr,art]=0.
Now, I would like to convert M into a square a x a matrix of ones and zeros (call it N) where if an article "art1" is in the same group as article "art2", we have N(art1,art2)=1 and N(art1,art2)=0 otherwise. N is clearly symmetric with 1's in the diagonal.
How do I construct N based on M?
Many thanks for your suggestions - and sorry if this is trivial (still new to python...)!
So you have a boolean matrix M like the following:
>>> M
array([[1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0],
[1, 0, 1, 0, 0, 0]])
>>> ngroups, narticles = M.shape
and what you want is a matrix of shape (narticles, narticles) that represents co-occurrence. That's simply the square of the matrix:
>>> np.dot(M, M.T)
array([[1, 0, 0, 1],
[0, 2, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 2]])
... except that you don't want counts, so set entries > 0 to 1.
>>> N = np.dot(M, M.T)
>>> N[N > 0] = 1
>>> N
array([[1, 0, 0, 1],
[0, 1, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 1]])