Related
I'm writing an algorithm that rotates a square matrix 90º degrees in-place, without using a second matrix. It works, but I've got one small problem that is troubling me.
So the basic, working algorithm is:
def rotate(matrix):
n = len(matrix)
# reverse rows
matrix.reverse()
# reflect
start = 0
for row in range(n):
for col in range(start, n):
matrix[row][col], matrix[col][row] = matrix[col][row], matrix[row][col]
start = start + 1
The idea is to pass a matrix defined as a list of lists, like [[1, 2, 3], [4, 5, 6], [7, 8, 9]].
Example input/output:
>>> some_matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> rotate(some_matrix)
>>> print(some_matrix)
[[7, 4, 1], [8, 5, 2], [9, 6, 3]]
Great. So, I was wondering if I could replace matrix.reverse() with something maybe a little more intuitive, like simply using slice indexing. So I wrote a new rotate, like this:
def rotate2(matrix):
n = len(matrix)
# reverse rows
matrix = matrix[::-1]
# reflect
start = 0
for row in range(n):
for col in range(start, n):
matrix[row][col], matrix[col][row] = matrix[col][row], matrix[row][col]
start = start + 1
Which SHOULD give me the same results, based on:
>>> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> b = a
>>> b = b[::-1]
>>> a.reverse()
>>> print(a)
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
>>> print(b)
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
>>> print(a==b)
True
However, when I use rotate2 on the same input/output example, I get:
>>> some_matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> rotate2(some_matrix)
>>> print(some_matrix)
[[9, 6, 3], [8, 5, 2], [7, 4, 1]]
So what am I missing here?
matrix = matrix[::-1] creates a new list and assigns it to the local name matrix; it does not modify the original list in-place.
matrix.reverse(), on the other hand, does modify the original list.
Consider these simple functions:
def r1(m):
m = m[::-1]
def r2(m):
m.reverse()
>>> x = [[1,2], [3,4]]
>>> r1()
>>> x
[[1,2], [3,4]]
>>> r2()
>>> x
[[3,4],[1,2]]
I have a 2D list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]], and I want to delete columns in a loop.
For example, columns with index: 0(first) and 2(last) - - the result after deletions should be: [8, 5, 5].
There is a problem, because when I delete the 0th column, the size of the list is decreased to (0,1), and the 2nd index is out of scope.
What is the fastest method to delete columns in a loop without the out-of-scope problem?
For a better picture:
[[1, 8, 3],
[4, 5, 6],
[0, 5, 7]]
There is no such shortcut in python except for iterating over all the list items and removing those index values.
However, you can use pandas which is meant for some other purpose but will do the task.
import pandas as pd
s = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
df = pd.DataFrame(s,columns=['val1','val2','val3'])
li = df.drop('val1',axis=1).values.tolist()
now li will look like this
[[8, 3], [5, 6], [5, 7]]
You can use numpy like this:
import numpy as np
my_list = np.array([[1, 8, 3], [4, 5, 6], [0, 5, 7]])
new_list = my_list[:, 1].copy()
print(new_list)
Output:
>>> [8, 5, 5]
Also numpy.delete(your_list, index, axis) is do the same job:
new_list = np.delete(my_list,(0, 2), axis=1)
(0, 2) is the indices of the columns 0 and 2
axis=1 says numpy that (0, 2) are columns indices not rows.
if you want to delete rows 0 and 2 you can change axis=1 to axis=0
Output is a little different:
>>> array([[8],
[5],
[5]])
For a pure python approach:
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
new_list = [value[1] for value in my_list]
print(new_list)
Output:
>>> [8, 5, 5]
L is 2D list:
print(map(lambda x: x[1:], L))
data= [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
index_to_remove=[0,2]
[list(x) for x in zip(*[d for i,d in enumerate(zip(*data)) if i not in index_to_remove])]
If I understood your question correctly, you want to keep the middle element (index 1) of each list,in that case I would suggest creating a new list. There could be other better ways, for sure. But you could try this, if this works for you:
twoD_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
def keep_col( twoD_list ,index_to_keep = 1):
final_list = []
for x in twoD_list:
final_list.append(x[index_to_keep])
return final_list
final_list = keep_col( twoD_list , 1)
Final output:
[8,5,5]
Assuming you always want only the second element and the inner lists always have at least two elements.
Pure python with list comprehension:
lst = [
[1, 8, 3],
[4, 5, 6],
[0, 5, 7],
]
filtered_lst = [
inner_element
for inner_lst in lst
for i, inner_element in enumerate(inner_lst)
if i == 1
]
print(filtered_lst)
# [8, 5, 5]
If you want you can the reassign the new list to the old variable:
lst = filtered_lst
The advantages of this method are:
no need to worry about the list being altered while you iterate it,
no need to import other libraries
list comprehension is built-in
list comprehension is often the fastest way to filter a list (see for example this article)
easier to read and maintain that other solutions (in my opinion).
Via itemgetter to extract the value at index 1.
from operator import itemgetter
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
result = list(map(itemgetter(1), my_list))
try this
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
filter_col=[0,2]
col_length=3
my_list=[[x[i] for i in range(col_length) if i not in filter_col] for x in my_list]
u do not want to directly mutate the list that you are working on
this performs a list comprehension to create a new list from the existing list
edit:
just saw u wanted only a flat list
assuming u only want one element for the list u can use
my_list=[x[1] for x in my_list]
This question already has answers here:
Add two matrices in python
(4 answers)
Closed 2 months ago.
To be honest, i don't really know how to properly explain what i want, so i better show it.
Basically what i want to do is add elements from 2 different 2D lists
a = [[5, 4, 5, 4], [4, 5, 6, 8]]
b = [[1, 2, 4, 5], [5, 6, 6, 2]]
And i wan't to merge them in a 2D array named c, so it should look something like this:
c = [[6, 6, 9, 9], [9, 11, 12, 10]]
I looked around, but sum and zip functions didn't give me the desired output. Thanks in advance for any help
A simple list comprehension and zip will be sufficient, Use:
c = [[x + y for x, y in zip(s1, s2)] for s1, s2 in zip(a, b)]
Result:
#print(c)
[[6, 6, 9, 9], [9, 11, 12, 10]]
What you are seeking is essentially matrix addition:
import numpy as np
a = np.array([[5, 4, 5, 4], [4, 5, 6, 8]])
b = np.array([[1, 2, 4, 5], [5, 6, 6, 2]])
c = a + b
Where "array" is numpy's vector and matrix object, so when you return "c", you should see
>>> c
array ([[6, 6, 9, 9],
[9, 11, 12, 10]])
In fact I could do this by using two zip functions, one inside another.
c = []
for x, y in zip(a, b):
array = []
for e1, e2 in zip(x, y):
array.append(e1+e2)
c.append(array)
print(c)
The output would be:
[[6, 6, 9, 9], [9, 11, 12, 10]]
Since you need the result in a new array, I'm creating a new matrix C as a copy of A.
So that i can easily add B to A.
You can do this:
c = a
for i in range(0,len(a)):
for j in range(0,len(a[0]):
c[i][j] = a[i][j] + b[i][j]
print(c)
You can use for loop to merge 2 arrays.
c = [[a[i][j] + b[i][j] for j in range(len(a[0]))] for i in range(len(a))]
You can use a nested loop to solve the problem.
a = [[5, 4, 5, 4], [4, 5, 6, 8]]
b = [[1, 2, 4, 5], [5, 6, 6, 2]]
c=[]
l=len(a)
for i in range(l):
temp=[]
l2=len(a[i])
for j in range(l2):
p=a[i][j]+b[i][j]
temp.append(p)
c.append(temp)
print(c)
You can use a loop for this.
from builtins import len
def insaneSum(x,y):
newTable = x #creates a copie of your first array
i = 0
j = 0
while i < len(x):
while j < len(x[i]):
newTable[i][j] = x[i][j] + y[i][j] #replaces value of copie for the sum
j = j+1
i = i+1
return newTable
a = [[5, 4, 5, 4], [4, 5, 6, 8]]
b = [[1, 2, 4, 5], [5, 6, 6, 2]]
c = insaneSum(a,b)
print(c)
E.g., if I've got
MAX_ALLOWED_DIFF = 3
nums=[1, 2, 4, 10, 13, 2, 5, 5, 5]
the output should be
groups = [[1, 2, 4], [10, 13], [2, 5, 5, 5]]
The context: I had a pandas.Series object nums and I used
nums = nums.diff().gt(DETECTION_MAX_DIFF_NS).cumsum()).apply(list).tolist()
to subsample in the same fashion but I noticed that there're a lot of duplicates in my Series nums and after I use .unique() method I don't have Series object anymore, I've got numpy.ndarray (1D) instead.
I believe I may use sth like pandas.Series(nums.unique) but I don't like this hack.
So we using drop_duplicates, keep nums stay in pd.Series
nums=nums.drop_duplicates()
nums.groupby(nums.diff().abs().gt(MAX_ALLOWED_DIFF).cumsum()).apply(list).tolist()
Out[447]: [[1, 2, 4], [10, 13], [5]]
Here's one approach -
>>> import numpy as np
>>> idx = np.r_[0,np.flatnonzero(np.abs(np.diff(nums))>MAX_ALLOWED_DIFF)+1,len(nums)]
>>> [nums[i:j] for (i,j) in zip(idx[:-1],idx[1:])]
[[1, 2, 4], [10, 13], [2, 5, 5, 5]]
Given that you've tagged with numpy too, here's one way to do it:
thr = 3
ix = np.flatnonzero(np.concatenate([[False], np.abs(np.diff(nums))>thr]))
np.split(nums, ix)
Output
[array([1, 2, 4]), array([10, 13]), array([2, 5, 5, 5])]
I would like a list to be stored into another list from right to left diagonally without importing anything if possible
eg. list =
[[1, 4, 6]
[6, 3, 7]
[2, 7, 9]]
say I'd like to store [6, 3, 2] into another list, how would i go about doing it? I have tried many ways for hours and still cant find a solution
With a list comprehension:
l =[[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
diagonal = [row[-i] for i, row in enumerate(l, start=1)]
print(diagonal)
Output
[6, 3, 2]
The following snipped
l =[[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
d = len(l)
a = []
for i in range(0,d):
a.append(l[i][d-1-i])
print(a)
results in the output you expected:
[6, 3, 2]
You can use a list comprehension and use list indexing twice to select your row and column:
L = [[1, 4, 6],
[6, 3, 7],
[2, 7, 9]]
n = len(L)
res = [L[i][n-i-1] for i in range(n)]
# [6, 3, 2]
An alternative formulation is to use enumerate as per #OlivierMelançon's solution.
If you can use a 3rd party library, you can use NumPy to extract the diagonal of a flipped array:
import numpy as np
arr = np.array(L)
res = np.diag(np.fliplr(arr))
# array([6, 3, 2])
When you want to create a list out from another list, list comprehension is a very good way to go.
a = yourlist
print([a[i][(i+1)*-1] for i in range(len(a))])
This list comprehension loops through the lists taking the the furthes back integer and the second furthes back and so on.
Using numpy and rotate (90)
import numpy as np
list = [[1, 4, 6],[6, 3, 7],[2, 7, 9]]
np.diag(np.rot90(array))
Output :
array([6, 3, 2])
or without using numpy:
list = [[1, 4, 6],[6, 3, 7],[2, 7, 9]]
res=[]
i=-1
for elm in list :
res.append(elm[i])
i-=1
print res
#[6, 3, 2]