Python Forum
Trying to figure out how list comprehensions work
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Trying to figure out how list comprehensions work
#1
Working through the docs cause I'm too broke to get traditional learning, and I'm at 5.1.4. Nested List Comprehensions.
the example in the docs is
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]

[[row[i] for row in matrix] for i in range(4)]
the output in IDLE is [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

As I interpret the listcomp: Do something with a variable with a list (or index) of 2nd variable representing a row in the previously defined list "matrix" for 2nd variable 4 times.
Sorry if you have to read that a few times to understand it, but I've read through the section about 20 times so far. So on to my questions:
Did I get the general interpretation correct?
Why does this swap the rows and columns? I'm not yet able to understand by reading it that that is what it is supposed to do.

Why does this just repeat the list 4 times instead of, well, anything else?
[[row for row in matrix]for i in range(4)]
 And last question, Why do I get a syntax error for both of these?
[[for row in matrix]for i in range(4)]
[row[for row in matrix]for i in range(4)]
The last example is just me breaking it in different ways to see how it breaks.
Reply
#2
Hello,

you should post this question in the public board and not as a private message.
Many people do have exactly have the same problem with understanding.
To understand list comprehension, it needs a little bit training.
For me is writing a list comprehension easier as reading the code from other peoples list comprehension.

Instead of using following code:
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
 
[[row[i] for row in matrix] for i in range(4)]
# better is
[[row[i] for row in matrix] for i in range(len(matrix))]
To explain it how this works exactly. I do not have time.
Later maybe in public discussion.

You should try this:
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
 
transposed_matrix = list(zip(*matrix))
# https://docs.python.org/3/library/functions.html#zip
zip take n arguments which have to be inalterable. It takes from all iterables the first element, yields it as a tuple, second element, yields it as a tuple, ..

So list(zip([1, 2], [3, 4])) will make the new list [(1, 3), (2, 4)]
Now the trick is, that the star * before matrix in zip will first do argument unpacking:

zip(*matrix)
# will unpack matrix as
zip([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12])
# remind that zip is in Python 3 an lazy evaluated iterable,
# so you've to use list or another built-in or function, which takes
# iterables and iterating over them.
Greetings
Andre
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply
#3
The way to think about list comprehensions (IMHO) is as a condensed form of loops that create lists. For example, these two bits of code create the same list:

by_loop = []
for x in range(10):
   by_loop.append(x ** 2)

by_comp = [x ** 2 for x in range(10)]
You can see the for loop in the comprehension, and you can see the squaring of x in the comprehension. The comprehension deals with the list stuff (initializing and appending) for you.

So we can unpack the nested list comprehension that you posted into a nested loop:

trans = []
for col in range(4):
   trans.append([])
   for row in matrix:
       trans[-1].append(row[col])
There is a tutorial on comprehensions in the tutorials section of these forums. Note that the tutorials section also has a stickied post with a list of free Python resources, some of which are probably easier to learn from than just reading the docs.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#4
So, based on what I am reading from ya'll, I am making a list of lists. This I should have already been able to figure out from previous reading. In this case, matrix is a list of 3 lists, and each list is an object wth an index value in 'matrix' that I can iterate over. In this comprehension each object defines the variable 'row'. So first part [row[i] for row in matrix] basically means iterate over each object in matrix and use data from the index value 'i' in each list to build a new list. (row[i] for row in matrix) should create a tuple, and str(row[i] for row in matrix) should create a string instead.

At this point I realize that you're right. This is more general theory than specific application and would have fit alot better in tutorial than coding help.

Second part [[....]for i in range(4)] defines 'i' and makes each of the created lists from the first part an object in a list.

Now I know why I am getting syntax errors and why and how it is transposing the values. Now if I wanted this to actually change the value of matrix then I should write it as matrix = [[row[i] for row in matrix] for i in range(4)]. [[row[i] for row in matrix] for i in range(len(matrix))] doesn't work because i is the index values of row, not matrix. When I tried that, I only got 3 objects and lost [4, 8, 12]. I tried [[row[i] for row in matrix] for i in range(len(row))], but row isn't defined before this line runs, so it doesn't know what the length is. Same error with [[row[i] for row in matrix] for i in row].

Thanks for the help, and I'll remember in the future that something like this is more of a tutorial than a coding question. But to get this on topic:

I need the aforementioned code to be able to calculate the length of each object in matrix so that I can transpose the values. Each object will have a variable length, and matrix might have a variable number of objects. I'm assuming the methods in previous answers is a good way to do this. Is that correct?
Reply
#5
[[row[i] for row in matrix] for i in range(len(matrix[0]))]
The above would be the correct way to generalize the code, for when the sub-lists are all the same length.

Transposing a list of list with variable length sub-lists brings up the question of what to do with the shorter lists. Say you have this matix:

matrix = [[1, 2], [3, 4, 5], [6, 7]]
What does the transposed matrix look like?

trans = [[1, 3, 6], [2, 4, 7], [None, 5, None]] #?
trans = [[1, 3, 6], [2, 4, 7], [0, 5, 0]] #?
trans = [[1, 3, 6], [2, 4, 7], [5]] #?
Remember that list comprehensions are another way to write a loop that creates a list. It is an easier, more compact way to write them; but as you are finding, they can be confusing. The more complicated the loop gets, the more confusing the list comprehension gets. Overly confusing code is bad code, so at a certain point it's just better to write out the full loop. I think that might be the case with transposing matrices with variable length rows.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Why do I have to repeat items in list slices in order to make this work? Pythonica 7 1,358 May-22-2023, 10:39 PM
Last Post: ICanIBB
  Beginner: Code not work when longer list raiviscoding 2 832 May-19-2023, 11:19 AM
Last Post: deanhystad
  How to work with list kafka_trial 8 2,054 Jan-24-2023, 01:30 PM
Last Post: jefsummers
  convert this List Comprehensions to loop jacklee26 8 1,533 Oct-21-2022, 04:25 PM
Last Post: deanhystad
  Are list/dict comprehensions interpreted really sequentially? anata2047 3 1,467 May-31-2022, 08:43 PM
Last Post: Gribouillis
  how does .join work with list and dictionaries gr3yali3n 7 3,330 Jul-07-2020, 09:36 PM
Last Post: bowlofred
  A strange list, how does this work? Pedroski55 1 1,726 May-13-2020, 11:24 PM
Last Post: snippsat
  Can't seem to figure out how to put all of the lists items from a loop into 1 list Cosmosso 4 2,782 Feb-21-2020, 02:40 PM
Last Post: Cosmosso
  Dictionary and tuples list comprehensions help paul41 2 2,399 Nov-29-2019, 06:59 PM
Last Post: perfringo
  List comprehensions-Wrong result RavCOder 4 2,307 Oct-08-2019, 10:16 AM
Last Post: RavCOder

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020