Python: Bug in writing a transpose function using lists - python-3.x

I have an assignment to do, which is:
Write a function transpose which takes in a matrix and transposes it. Basically, this converts a m x n matrix into a n x m matrix.
I wrote a code which seems sensible, but it doesnt get me the result I want. Can anyone point out what is wrong with my code?
def transpose(matrix):
new_matrix=[[]]*len(matrix[0])
for row in matrix:
i=0
for j in row:
new_matrix[i]+=[j]
i+=1
return new_matrix
Test case:
print(transpose([[ 1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]))

If you use the * to multiply some values in a list-initialisation, be careful. You might end up with references that point multiple times to the same value:
l = [ [] ]*3
print(l)
l[1].append(34) # change only "the first" list by appending smth
print(l)
Output:
[[], [], []]
[[34], [34], [34]] # they are all "the same data" reference
There is an built-in zip() that does exactly your transposing:
l = [[ 1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
l_t = [ list(x) for x in zip(*l)] # one-line solutions for transposing ;)
print(l)
print(l_t) # transposed
Zip has the limitation that it only works to the length of the smallest sublists - yours are all equal so all is fine.
Output:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
If you ever need a zip that takes the longest list, itertools.zip_longest(..) can be used, it takes a default param that is substituted for any shorter list-items that are not there.
Btw. just list(zip(l)) looks like this: [(1,5,9),(2,6,10),(3,7,11),(4,8,12)] - it create tuples over the same indexes of the parts of the iterable you put into it.
By hand:
l = [[ 1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
l2 = []
for colIdx in range(len(l[0])): # 0-3 iterate over the inner indexes first
newRow = []
for rowIdx in range(len(l)): # 0-2 then over the outer ones
newRow.append(l[rowIdx][colIdx])
l2.append(newRow)
print(l2) # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

What i meant was something like this:
def t(array): #The original array has size mxn
duplicate = [[0 for x in range(len(array))] for y in range(len(array[1]))] #You create an array of size nxm, which is filled with zeros
for i in range(len(array)): #Loop over the rows
for j in range(len(array[i])): #Then loop over the columns
duplicate[j][i] = array[i][j] #Replace j,i or duplicate with i,j th element of original
return duplicate
Now,
>>> t([[ 1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Related

print values from a list in vertical order for many lists

I'm having trouble printing data from a list vertically , the list is as shown below
[[1, 4, 5], [4, 6, 8], [8, 3, 10]]
I want to print the data into a new list as follows:
[[1, 4, 8], [4, 6, 3], [5, 8, 10]]
I'm having trouble doing it when the lists get longer, as it is a nested list
If the data is only numbers / integers, then you might want to use numpy for this. It will be faster too.
import numpy
givenList = [[1, 4, 5], [4, 6, 8], [8, 3, 10]]
toNumpy = numpy.array(givenList) #convert to numpy array
toNumpy = toNumpy.T #transpose
toList = toNumpy.tolist() #convert back to list
print(toList)
# output : [[1, 4, 8], [4, 6, 3], [5, 8, 10]]
I think you are looking for zip.
l = [[1, 4, 5], [4, 6, 8], [8, 3, 10]]
z = zip(*l)
print('\n'.join(map(str, z)))
# Output is:
# (1, 4, 8)
# (4, 6, 3)
# (5, 8, 10)
It does produce tuples instead of lists, but that is usually easily dealt with, and if you are just iterating over them, then it probably doesn't matter.
l = [[1, 4, 5], [4, 6, 8], [8, 3, 10]]
z = map(list, zip(*l))
print('\n'.join(map(str, z)))
Will give you the same result, but will print them out as lists.

Iā€™m trying to flip every second sub list in a list of lists. Does any one have suggestions?

My_list= [[1,2,3],[4,5,6],[7,8,9]] ā€”ā€”ā€”-> [[1,2,3],[6,5,4],[7,8,9]]
I tried using this with out success :
for i my_list:
if my_list.index(i) != 0:
i = i[::-1]
Since Python for loops create local variables, you have to index into the outer list indexes and use % 2 == 1 to detect sublists with odd indexes.
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
for index, sublist in enumerate(my_list):
if index % 2 == 1:
my_list[index] = sublist[::-1]
print(my_list)
Outputs
[[1, 2, 3], [6, 5, 4], [7, 8, 9], [12, 11, 10]]
Another option (in addition to #DeepSpace answer) is using Python's slicing notation (link) and assigning to slice (link):
In this example, we create slice starting from index 1 and step 2 and assign reverse sublist to it:
my_list = [[1,2,3],[4,5,6],[7,8,9]]
my_list[1::2] = (v[::-1] for v in my_list[1::2])
print(my_list)
Prints:
[[1, 2, 3], [6, 5, 4], [7, 8, 9]]

Access non-sequential multiple entries in a list of lists

I have a matrix of M vectors where each vector is of size N (NxM).
I also have a Boolean vector of size L>=M, with exactly M entries = True.
I want to create a list of lists and place the M vectors where the Boolean vector is True in same order as they are in the matrix, and the rest I want to be empty lists
Example: M = 3, N = 4, L = 5
mat = np.array([[1, 5, 9],
[2, 6, 10],
[3, 7, 11],
[4, 8, 12]])
mask = [True, False, True, True, False]
I want to create the following:
res = [ [1, 2, 3, 4], [], [5, 6, 7, 8], [9, 10, 11, 12], []]
Accessing it can be done using:
data = [res[idx] for idx in range(len(res)) if mask(idx)]
However, creating it is a bit problematic.
I tried creating a list of empty lists, but I can't access all relevant entries at once.
Is there an elegant way of doing it?
Here is how I would do it:
mi = iter(mat.T.tolist())
[(m or []) and next(mi) for m in mask]
# [[1, 2, 3, 4], [], [5, 6, 7, 8], [9, 10, 11, 12], []]
As you are already using a list comprehension to get the data back from res, I would do a similar thing to create res in the first place.
mask_cs = np.cumsum(mask) - 1 # array([0, 0, 1, 2, 2]) , gives the corresponding index in mat
res = [mat[:, mask_cs[idx]].tolist() if mask[idx] else [] for idx in range(L)]
As alternativ, which accesses all columns of mat at once, on can create an intermediate array with size [N, L]
import numpy as np
res = np.zeros((N, L)) # Create result array
res[:, mask] = mat # Copy the data at the right positions
res = res.T.tolist() # Transform the array to a list of lists
for idx in range(L): # Replace the columns with empty lists, if mask[idx] is False
if not mask[idx]:
res[idx] = []
We could make use of np.split for some elegance, like so -
In [162]: split_cols = np.split(mat.T,np.cumsum(mask)[:-1])
In [163]: split_cols
Out[163]:
[array([[1, 2, 3, 4]]),
array([], shape=(0, 4), dtype=int64),
array([[5, 6, 7, 8]]),
array([[ 9, 10, 11, 12]]),
array([], shape=(0, 4), dtype=int64)]
So, that gives us a list of 2D arrays. For the desired output of list of lists, we need to map them to such -
In [164]: list(map(list,(map(np.ravel,split_cols))))
Out[164]: [[1, 2, 3, 4], [], [5, 6, 7, 8], [9, 10, 11, 12], []]
Alternatively, we can use lambda if that looks more elegant to some -
In [165]: F = lambda a: np.ravel(a).tolist()
In [166]: list(map(F,split_cols))
Out[166]: [[1, 2, 3, 4], [], [5, 6, 7, 8], [9, 10, 11, 12], []]

How to use list comprehensions for this?

I want to take input of 2 numbers: the number of rows and the number of columns. I then want to use these to output a matrix numbered sequentially. I want to do this using a list comprehension. The following is a possible output.
>>>> my_matrix = matrix_fill(3, 4)
>>>> my_matrix
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
I am using the following code to output a sequentially numbered list:
def matrix_fill(num_rows, num_col):
list=[i for i in range(num_col)]
return (list)
I cannot, however, figure out how to make the sequential list of numbers break into the separate lists as shown in the output based on num_rows.
I don't think you need itertools for that. The range function can take a step as a parameter. Like this:
def matrix_fill(rows,cols):
return [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)]
And then it works as expected.
>>> matrix_fill(3,4)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
Let's break this down a little bit and understand what's happening.
>>> [x for x in range(1,3*4+1)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
So what we want to do is to get a new slice every four elements.
>>> [x for x in range(1,3*4+1)][0:4]
[1, 2, 3, 4]
>>> [x for x in range(1,3*4+1)][4:8]
[5, 6, 7, 8]
>>> [x for x in range(1,3*4+1)][8:12]
[9, 10, 11, 12]
So we want to iterate over the elements of the list[x for x in range(1,3*4+1)] of length "rows*cols" ( 3 * 4 ), create a new slice every "cols" number of elements, and group these slices under a single list. Therefore, [[x for x in range(1,rows*cols+1)][i:i+cols] for i in range(0,rows*cols,cols)] is a suitable expression.
Nest a list comprehension inside another one, use itertools.count() to generate the sequence:
import itertools
rows = 3
cols = 4
count_gen = itertools.count() # pass start=1 if you need the sequence to start at 1
my_matrix = [[next(count_gen) for c in range(cols)] for r in range(rows)]
print(my_matrix)
# prints: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
# As a function
def matrix_fill(rows, cols):
count_gen = itertools.count()
return [[next(count_gen) for c in range(cols)] for r in range(rows)]
If you used the numpy module, the method is extremely simple, with no list comprehension needed.
my_matrix = np.arange(1, 13).reshape(3,4)
Printing the variable my_matrix shows
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]

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