[Tutor] The Python way and two dimensional lists

Alan Gauld alan.gauld at yahoo.co.uk
Sun Nov 21 19:55:20 EST 2021


On 22/11/2021 00:13, Phil wrote:
> I hope my questions are not becoming too tiresome.

Not at all, its the only way to learn.

> It will require a major effort to rewrite my use of lists in the Python 
> way and so I want to make sure that the first steps are correct.

Good idea!

> first index refers to the columns and the second to the rows.

You can use the indices any way you like but this way will
make your table appear sideways if you print it out with
print()

But...

> solution = [[0 for i in range(num_cols)] for j in range(num_rows)]

This is a list of lists.
Each inner list is  the number of *columns* wide - so it
must represent a *row* not a column.
And you have as many inner lists as you have rows so
that means each position inside a row represents a column entry.



> solution[1][0] = {5}

So this represents the second row, first column.

> ...
> solution[0][1] = {1,2,3}

And this is the first row, second column.

> for col in solution:
>      print(col[0])
> for row in solution:
>      print(row[1])

These two loops are both extracting the same objects,
just printing a different item. Let's rewrite it using
different names for the variable (since the loop doesn't
care about the name):

for x in solution: print(x[0])
for x in solution: print(x[1])

I reused the name x since the loop doesn't care.
But can you see how you are repeating the exact same loop.

Meaningful variable names are great because they show your
intentions. But they can trick us into thinking they
mean something that they don't, just because we want them to!

> If I want to refer to column 6, is it the Python way to say x = col[6]?

Yes, provided you have first set x to a row.
And of course 6 returns the 7th column since its
zero based indexing.

Also, using python "2D" lists there is no way to
access the entire column (in your example) you can
only access a whole row.

You can build a copy of a column easily enough with:

col6 = [row[5] for row in solution]

But if you change any values you need to regenerate
the copy so it's not exactly efficient.

> Also regarding enumeration. The following is a slight modification to 
> Mats code and it gives me exactly what I want:
> 
> row = [{7,3},{5},{4,8,6},{7,8},{1},{9,3},{7,9},{4,6,3},{2}]
> 
> enum_row = enumerate(row)

This is unused and gets thrown away as soon as
you enter the loop.

> row_position = []
> 
> for index, enum_row in enumerate(row):

enum_row is a bad name to use here IMHO.
its actually each set within the row.
And the sets represent the cell content
(as I understand your design)
So I'd prefer

for index,cell in enumerate(row):

>          if i in enum_row:#r:
>              icount += 1
>              row_position.append(index)

And this becomes

if i in cell:
   icount += 1
   row_position.append(index)

> Now returning to the two dimensional list above and assuming that col[0] 
> is referring to a row (just for this question only). I'm not sure if 
> this is correct because of an error in another section of the code

I think you need to swap your understanding of rows/cols.
You access the rows directly, the columns you need to
construct on demand.

col[0] doesn't refer to anything because col doesn't exist.
Even if you created the col as illustrated above col[0] would
be the first cell only, not a row.

But you can get the row using solution[0]

> enum_row = enumerate(col[0]) # instead or row

Again, I don't know what you think this is doing
but it returns a generator(pedantically, an enumerate object)
which you never use and then:

> for index, enum_row in enumerate(col[0]): # instead or row

Assuming col should be solution...

This sets enum_row to the second value of the first returned
tuple from enumerate(), ie the first row.

So now you want(I think) to test every cell within that row
using the exact code you had above. So you need two nested loops.

>      print('enum_row ',enum_row )
>          if i in enum_row:
>              icount += 1
> 
> This is where the error is occurring (also from Mats code):
> 
> for s in set_list:

Where is set_list created?

>      for r in col[0]: # instead of row:
>          if s.issubset(r):
>              pairs[tuple(sorted(s))] += 1
> 
> Traceback (most recent call last):
>    File "/usr/lib/python3.9/idlelib/run.py", line 559, in runcode
>      exec(code, self.locals)
>    File "/home/phil/Python/set_count2.py", line 75, in <module>
>      if s.issubset(r):
> TypeError: 'int' object is not iterable
> 
> Confusion is setting in. I think my use of enumerate is correct and I 
> think the way that I'm referencing a row from the solution list is 
> correct. 

Sadly, I think both of those assumptions are wrong!

What I think you are trying to do, and using the name
you started with is:


for irow, row in enumerate(solution):
    for icell, cell in enumerate(row):
        if value in cell:
           pairs[tuple(sorted(cell))] += 1
           table_position.append(irow,icell)  # I think...

Which hopefully reads more clearly and makes sense.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Tutor mailing list