Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a Matrix With a Generator

I have a list:

l = [1,2,3]

I want my output to be:

m = [(1-1, 1-2, 1-3),(2-1, 2-2, 2-3), (3-1, 3-2, 3-3)]
m = [[0, -1, -2], [1,0,-1], [-2,-1,0]]

I wrote this function and it works fine:

def matrixer(l):
    matrix = []

    for data in l:
        column = []
        column.append(data - l[0])
        column.append(data - l[1])
        column.append(data - l[2])
        matrix.append(column)

    return matrix

But this doesn't scale well - as my list could have up to 100's of values and I don't want to keep adding the below line of code for each value in my list:

column.append(data - l[n])

I've never used generators before but it sounds like the solution would involve one. I've always tried a while loop, but it doesn't quite get me there as I run into the same issue.

like image 523
mk8efz Avatar asked Jan 04 '23 23:01

mk8efz


2 Answers

Using two for loops we have to reset the sub_answer every time. This looks messy so maybe another option; can be found below:

l = [1,2,3]
answer = []
for each in l:
  sub_answer = []
  for every in l:
    sub_answer.append(each-every)
  answer.append(sub_answer)
  sub_answer = []
print(answer)
#[[0, -1, -2], [1, 0, -1], [2, 1, 0]]

Removing a for loop for a list comprehension. Now we don't need sub_answer:

l = [1,2,3]
answer = []
for each in l:
  answer.append([each-x for x in l])
print(answer)
#[[0, -1, -2], [1, 0, -1], [2, 1, 0]]

l is scale able. We are iterating through the list and then appending to a new list that we created using a list comprehension which we are subtracting the each variable by going through the list again.

If we change l to be l = [1,2,3,4,5,6,7] we get:

[[0, -1, -2, -3, -4, -5, -6], [1, 0, -1, -2, -3, -4, -5], [2, 1, 0, -1, -2, -3, -4], [3, 2, 1, 0, -1, -2, -3], [4, 3, 2, 1, 0, -1, -2], [5, 4, 3, 2, 1, 0, -1], [6, 5, 4, 3, 2, 1, 0]]

As a note (3-1 is not -2... it's 2....)


We used one list comprehension why not use two?!?!?!: If you don't want a for loop and just want to use list comprehension:

l = [1,2,3]
print([[each-x for x in l] for each in l])
#[[0, -1, -2], [1, 0, -1], [2, 1, 0]]

gives the same result, but I think for loops are more readable if you are learning or on a team.

like image 72
MooingRawr Avatar answered Jan 16 '23 18:01

MooingRawr


double list comprehension does it in one line:

def matrixer(l):
    return [[e - d for d in l] for e in l]
  • inner listcomp to create the inner line
  • outer listcomp to create rows

result with your input:

[[0, -1, -2], [1, 0, -1], [2, 1, 0]]

list comprehensions are highly optimized memory-wise (less reallocations) & CPU-wise (less instructions) so replacing your double loop + append with 2 nested list comprehensions like that will speed up your code a lot.

like image 37
Jean-François Fabre Avatar answered Jan 16 '23 18:01

Jean-François Fabre