Met with "Index Out of Range" when Trying to Transpose Matrix - python

I'm trying to figure out how to transpose a matrix with vectors that contain an unequal amount of elements.
I'm just learning to program and I'm currently working through the Python Tutorial and I'm stuck on an example listed in "Nested List Comprehensions" here: https://docs.python.org/3/tutorial/datastructures.html#nested-list-comprehensions.
Here is a very slight variation of example shown in the Python Tutorial:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
[[row[i] for row in matrix] for i in range(3)]
I decided to create my own solution for the example because I wanted the code to be a bit more dynamic, which was this:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
[[row[i] for row in matrix] for i in range(len(matrix))]
However, shortly after coming up with my solution I noticed there was a lot of ways it could still break and tried figuring out a solution that wouldn't break under any of the following scenarios:
# Scenario 1: Vectors of unequal length sizes.
matrix = [
[1, 2, 3, 4],
[5, 6, 7],
[8, 9, 10, 11]
# Scenario 2: len(vector) > len(matrix)
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8]
]
# Scenario 3: len(vector) < len(matrix)
matrix = [
[1, 2],
[3, 4],
[5, 6],
[7, 8]
]
If anyone can come up with a solution using nested list comprehensions that would be able to handle all 3 of these scenarios, I would greatly appreciate your help.

disclaimer: all of this assumes your rows are all of the same length (as should be for a matrix).
just a minor tweak will do:
[[row[i] for row in matrix] for i in range(len(matrix[0]))]
the point is to have i in the range of the length of the rows of you matrix len(matrix[0]) (i am using the first row here as it always should exist).
a more elegant way is using zip:
list(zip(*matrix))
although you will get tuples as rows. if you need lists you can do:
[list(row) for row in zip(*matrix1)]

This works for both equal and unequal row lengths by collapsing the sparse rows to the left:
[[row[i] for row in matrix if i < len(row)] for i in range(max(len(r) for r in matrix))]
So scenario 1
matrix = [
[1, 2, 3, 4],
[5, 6, 7],
[8, 9, 10, 11]]
becomes
[[1, 5, 8],
[2, 6, 9],
[3, 7, 10],
[4, 11]]

Related

Transforming a matrix by placing its elements in the reverse order of the initial in python

im looking to solve the problem mentioned in the title without any specific functions that may or may not exist for this[]. Something along the lines of using mostly loops.
I tought about reversing each individual row using list.reverse() and then moving the rows around but im not sure how to implement it.
try this new realization and this will not change the original Matrix
Matrix = [[1,2,3],[4,5,6],[7,8,9]]
newMatrix = []
for line in range(len(Matrix)):
newMatrix.append(sorted(Matrix[line],reverse=True))
newMatrix.reverse()
print(newMatrix)
print(Matrix)
output:
[[9, 8, 7], [6, 5, 4], [3, 2, 1]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Try This
Matrix = [[1,2,3],[4,5,6],[7,8,9]]
newMatrix = []
for line in range(len(Matrix)):
Matrix[line].reverse()
newMatrix.append(Matrix[line])
newMatrix.reverse()
print(newMatrix)
output
[[9, 8, 7], [6, 5, 4], [3, 2, 1]]

python : extract submatrices from indices

I have a matrix and a list of indices for both dimensions.
A = [[1,2,3],[4,5,6],[7,8,9]]
idx = [1,3,4]
idy = [2,5,7]
What is the similar notation from Matlab doing A(idx,idy) in Python?
Here is my exmple:
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
idx = [0, 1]
idy = [1, 2]
a = [[A[ix][iy] for iy in idy] for ix in idx]
print(a)
From:
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
I am obtaining the submatrix according to my indexes idx and idy:
[
[2, 3],
[5, 6]
]
Please keep in mind that in python indexing start from 0 so giving the fact that here we have a 3x3 matrix the smallest index is 0 and the biggest is 2 for each row and column.
Is this what you are looking for? Please let me know.

How for loop is transposing matrix in this case?

matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
**[[row[i] for row in matrix] for i in range(4)]**
how this loop is transposing the matrix, kindly explain in detail, if possible step after every loop.
You unroll list comprehensions from right to left:
matrix = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
inver = [[row[i] for row in matrix] for i in range(4)]
Unrolled:
k = []
for i in range(4):
l = []
for row in matrix:
l.append(row[i])
k.append(l)
put in some print statements to figure it out. See How to debug small programs (#1) and read up in Converting List Comprehensions to For Loops in Python
As a sidenote - why come from the official tutorial pages here to get it explained? Why not also cite them?
https://docs.python.org/3/tutorial/datastructures.html#nested-list-comprehensions

Create and fill each list within a list

I learned to create and manage nested lists by building a NxM matrix and filling it with random integers.
I've solved it via a simple one-liner and struggled to write a comprehensive solution.
I call the first solution as a cheating because I got this tip from this website, but didn't completely understand how it works. So, I've tried to write a more detailed piece of code on my own, which was difficult, and I'm not completely sure I got it right.
The original solution:
from random import randint
size_n = int(input("Number of lists N "))
size_m = int(input("Number of elements M "))
matrix = [[randint(1,9) for m in range(size_m)] for n in range(size_n)]
print(matrix)
I had a hard time to create a list of list with the correct levels of loops in loops. I end up with the temporary matrix, but I'm not sure it's good solution.
The final solution:
from random import randint
size_n = int(input("Number of lists N "))
size_m = int(input("Number of elements M "))
matrix = []
for n in range(size_n):
tmp = []
for m in range(size_m):
tmp.append(randint(1,9))
matrix.append(tmp)
print(matrix)
Can you help me to understand what is the correct solution for the task?
P.S. Is it normal for developer to look for another solution if the code just works but you think it might be prettier?
matrix = [[randint(1,9) for m in range(size_m)] for n in range(size_n)]
Let's say our size_n is 5, for an example. Then range(size_n) gives
[0, 1, 2, 3, 4]
E. g. a list of 5 consecutive integers starting with 0. If you do something for each element of the list, that creates another list of the same size, for example:
>>>[88 for n in range(size_n)]
[88, 88, 88, 88, 88]
You are, of course, not limited by simple numbers, you can create, basically, anything. For example, empty lists:
>>>[[] for n in range(size_n)]
[[], [], [], [], []]
Then, of course, the inner lists don't have to be empty, you can populate them with numbers:
>>>[[1, 2, 3] for n in range(size_n)]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Or you can use another range expression inside:
>>> [[range(1, 4)] for n in range(5)]
[[[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]], [[1, 2, 3]]]
And you can use list comprehension on those inner lists just the same way:
>>> [[randint(1, 9) for m in range(1, 4)] for n in range(5)]
[[8, 4, 3], [6, 7, 2], [6, 8, 2], [9, 6, 1], [9, 1, 2]]
You can go deeper and deeper until you're bored or out of memory:
>>> [[[randint(1, 9) for n in range(1, 5)] for n in range(1, 4)] for n in range(5)]
[[[2, 9, 6, 1], [6, 7, 4, 5], [5, 9, 1, 7]], [[5, 2, 9, 3], [1, 8, 9, 7], [8, 4, 4, 8]], [[4, 4, 7, 9], [7, 1, 4, 2], [7, 8, 7, 3]], [[4, 4, 9, 9], [8, 8, 9, 5], [6, 1, 3, 9]], [[5, 9, 3, 2], [7, 5, 4, 7], [7, 7, 4, 3]]]
Nested list comprehension is usually the right solution, they are easy to read once you get used to the notation. Nested loops are OK too.
There's nothing wrong with looking for better ways to re-write your working code (I'd say, rather, it's wrong not to look), unless you develop an unhealthy obsession with it.
For Python 3 range(5) actually doesn't give [0, 1, 2, 3, 4] directly, but for this task it's effectively the same thing.

Multidimensional slicing in raw Python

Let's say I have an array defined as
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
and I wanted to get a vertical slice, returning [2, 5, 8]. Is there any way to do this with slicing syntax in straight Python? When I try to look up multidimensional slicing, the only results I tend to see are all talking about numpy, and using the syntax discussed there gives errors in raw Python.
I don't know of a direct way to get a vertical slice and this is probably more expensive than the list comprehension answer but still
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
list(zip(*z)[1])
[2, 5, 8]
Or this may be slightly less expensive
from itertools import izip, islice
list(*islice(izip(*z), 1, 2))
[2, 5, 8]
Sure. You could generally use a for loop. Or simply you could code like:
>>> test = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
>>> [row[1] for row in test]
[2, 5, 8]
This piece of code will generate a new list for a vertical slice. If you really need a slice operation, the following code would be useful:
>>> [item for sublist in test for item in sublist][1::len(test[0])]
[2, 5, 8]

Categories