Element wise addition of two n dimensional lists - python-3.x

When I need to add two 2D lists element wise, the approach I am using is
l1 = [[1, 1, 1],
[2, 2, 2],
[3, 3, 3]]
l2 = [[1, 1, 1],
[2, 2, 2],
[3, 3, 3]]
new = list(map(lambda e: [sum(x) for x in zip(*e)], zip(l1, l2)))
print(new)
output : [[2, 2, 2],
[4, 4, 4],
[6, 6, 6]]
This code is already difficult to read.
So how would I add two n dimensional lists element wise? Is there a pythonic way to do it or should I use numpy?

Related

How do I itterate over a nested list to get a list of possible outcomes with unique elements in it?

Given a nested list say:
a = [[1, 5, 100],
[2],
[2, 100]]
The desired result to be obtained is as follows:
[[1, 2, 5], [1, 2, 100], [5, 2, 100], [100, 2, 5]]
Here is my code, but it does not give the output as desired. I am unable to progress further:
arr = [[i] for i in a[0]]
def poss(j, arr, tmp):
for i in range(len(tmp)):
arr[i] = tmp[i] + [j]
print(arr)
for i in a[1:]:
tmp = [k for k in arr] # deepcopy of arr
for j in i:
poss(j, arr, tmp)
Output for above code:
[[1, 2], [5, 2], [100, 2]]
[[1, 2, 5], [5, 2, 5], [100, 2, 5]]
[[1, 2, 100], [5, 2, 100], [100, 2, 100]]
I also feel this code is inefficient on large data, is that so? I'm looking for a better code to get the result.
This problem can be solved by using itertools module of python.
The itertools.combinations() function returns all the possible subsets of the given set without repetition of elements.
import math
import itertools
a = [[1, 5, 100],
[2],
[2, 100]]
dimx = max([len(el) for el in a])
uniqueEls={}
for el in a:
for subel in el:
uniqueEls[subel] = uniqueEls.get(subel,0)
desiredArr= [list(x) for x in list(itertools.combinations(uniqueEls.keys(), dimx))]
print(desiredArr)
[[1, 5, 100], [1, 5, 2], [1, 100, 2], [5, 100, 2]]

divides each element of the matrix by 2 if the element is an even number

i need to write a function in python that takes a matrix as an argument and divides each element of the matrix by 2 if the element is an even number (otherwise, does nothing).
i also need to use list comprehension for this.
as an example, if i have a matrix like m = [[5, 4], [2, 3], [6, 7]] output: [[5, 2], [1, 3], [3, 7]]
Thanks.
def f(matrix):
return [ [x//2 if x%2==0 else x for x in m ] for m in matrix]
print(f([[5, 4], [2, 3], [6, 7]]))

sort a list according to keys and for elements with same keys as per values in python

I started learning python recently. I am trying to sort a list of lists similar to this. However, I'm not able to find the correct method to do so please help.
Consider the list [[1,4], [3,3], [3,2] ,[1,2], [1,3], [2,3], [1,5]]
now, using
def keyFunc(j):
return j[0]
job = sorted(job, key=keyFunc, reverse=True)
I got it down to [[all 3s], [all 2s], [all 1s]]
However, now I want to further sort it so that the lists with common keys are in the order of descending values of their keys.
i.e. [[3,3], [3,2], [2,3], [1,5], [1,4], [1,3], [1,2]]
How does one do that in python?
Why do you use a wrong key function when not using a key function already does what you want?
>>> sorted(job, reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
Or since you're assigning back to job anyway, you might want to do job.sort(reverse=True) instead of creating a new list.
You can change the keyFunc to be like
def keyFunc(j):
return j[0]*10+j[1]
or
ls = [[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
sorted(ls, key=lambda x: x[0]*10+x[1], reverse=True)
That will sort both of the numbers as you described.
I think you can just negate the sorting keys to sort descending twice:
>>> lst = [[1,4], [3,3], [3,2] ,[1,2], [1,3], [2,3], [1,5]]
>>> sorted(lst, key=lambda x: (-x[0], -x[1]))
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
(-x[0], -x[1]) will first sort by the first item, then if any ties occur sort on the second item, both in descending manner. We can make it descending by negating with the minus - sign.
But as suggested by #Heap Overflow, we don't need to do this because we can just pass reverse=True, and sorted() will naturally sort by the first item then the second in descending order. No need for a sorting key.
You can test this by running the following:
>>> sorted(lst, reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
>>> sorted(lst, key=lambda x: (x[0], x[1]), reverse=True)
[[3, 3], [3, 2], [2, 3], [1, 5], [1, 4], [1, 3], [1, 2]]
Which both give the same results.

idiom for getting contiguous copies

In the help of numpy.broadcst-array, an idiom is introduced.
However, the idiom give exactly the same output as original command.
Waht is the meaning of "getting contiguous copies instead of non-contiguous views."?
https://docs.scipy.org/doc/numpy/reference/generated/numpy.broadcast_arrays.html
x = np.array([[1,2,3]])
y = np.array([[1],[2],[3]])
np.broadcast_arrays(x, y)
[array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]), array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])]
Here is a useful idiom for getting contiguous copies instead of non-contiguous views.
[np.array(a) for a in np.broadcast_arrays(x, y)]
[array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]), array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])]
To understand the difference try writing into the new arrays:
Let's begin with the contiguous copies.
>>> import numpy as np
>>> x = np.array([[1,2,3]])
>>> y = np.array([[1],[2],[3]])
>>>
>>> xc, yc = [np.array(a) for a in np.broadcast_arrays(x, y)]
>>> xc
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
We can modify an element and nothing unexpected will happen.
>>> xc[0, 0] = 0
>>> xc
array([[0, 2, 3],
[1, 2, 3],
[1, 2, 3]])
>>> x
array([[1, 2, 3]])
Now, let's try the same with the broadcasted arrays:
>>> xb, yb = np.broadcast_arrays(x, y)
>>> xb
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
Although we only write to the top left element ...
>>> xb[0, 0] = 0
... the entire left column will change ...
>>> xb
array([[0, 2, 3],
[0, 2, 3],
[0, 2, 3]])
... and also the input array.
>>> x
array([[0, 2, 3]])
It means that broadcast_arrays function doesn't create entirely new object. It creates views from original arrays which means the elements of it's results have memory addresses as those arrays which may or may not be contiguous. But when you create a list you're creating new copies within a list which guarantees that its items are stored contiguous in memory.
You can check this like following:
arr = np.broadcast_arrays(x, y)
In [144]: arr
Out[144]:
[array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]]), array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])]
In [145]: x
Out[145]: array([[1, 2, 3]])
In [146]: arr[0][0] = 0
In [147]: arr
Out[147]:
[array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]), array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])]
In [148]: x
Out[148]: array([[0, 0, 0]])
As you can see, changing the arr's elements is changing both its elements and the original x array.

Adding two list in a list in python

Can anyone help me. This is what i want to do.
x = [[1,2,3,4,5],[6,7,8,9,10]]
y= [0,1]
desired output = [
[[1,2,3,4,5],[0,1]],
[[6,7,8,9,10],[0,1]]
]
I try putting it in a for loop
>>> x = [[1,2,3,4,5],[6,7,8,9,10]]
>>> for value in x:
... a = []
... a += ([x,y])
... print(a)
...
[[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], [0, 1]]
[[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], [0, 1]]
I also tried doing this
>>> for value in x:
... a = []
... a += ([x,y])
... print(a)
...
[[1, 2, 3, 4, 5], [0, 1]]
[[1, 2, 3, 4, 5], [0, 1]]
[[1, 2, 3, 4, 5], [0, 1]]
[[1, 2, 3, 4, 5], [0, 1]]
[[1, 2, 3, 4, 5], [0, 1]]
Thank you for helping. I need it for putting label on my data for neural networks.
You can use a list comprehension, and iterate over each sublist in x. Since you're inserting y into different sublists, you might want to insert a copy of the list, not the original.
[[i, y[:]] for i in x]
Or,
[[i, y.copy()] for i in x]
[[[1, 2, 3, 4, 5], [0, 1]], [[6, 7, 8, 9, 10], [0, 1]]]
The copy is done as a safety precaution. To understand why, consider an example,
z = [[i, y] for i in x] # inserting y (reference copy)
y[0] = 12345
print(z)
[[[1, 2, 3, 4, 5], [12345, 1]], [[6, 7, 8, 9, 10], [12345, 1]]] # oops
Modifying the original y or the y in any other sublist will reflect changes across all sublists. You can prevent that by inserting a copy instead, which is what I've done at the top.
Try this:
for i in range(len(x)):
z[i] = [x[i],y];

Resources