[Tutor] Creating a two dimension set

Cameron Simpson cs at cskk.id.au
Sun Oct 31 16:08:08 EDT 2021


On 31Oct2021 15:56, Phil <phillor9 at gmail.com> wrote:
>As an example, if I wanted to create a two dimension list I would write:
>
>num_rows = 9
>num_cols = 9
>
>self.solution = [[None] * num_cols for _ in range(num_rows)]

Keeping in mind that this is a list of lists. Also, you're preallocating 
num_cols*nul_rows of storage. That can be wasteful if you're not filling 
much of it in.

>In my current creation I need a two dimension set and so I have used, 
>again for example:
>
>result = set(self.solution[row][col]) - 3

This line makes no sense to me: you cannot subtract a number from a set.  
And initialising a set requires an iterable - does your list-of-lists 
itself contain lists? The "None" in your first example suggests maybe 
not.

>However, my code has grown and I find that I'm making mistakes and it 
>would be much simpler if I'd created a two dimension set in the first 
>place rather that converting the list to a set every time I need to 
>access it.
>
>I could, I suppose, use two for loops to create and initialise the set 
>but there must be a simpler and less tedious way.

I do not fully understand your use case, partly because your second 
example is not sane Python.

I'm also not sure you mean "set". Can you tell us in more detail what 
you're doing, maybe a very small example programme?

Might I suggest a dict indexed by a 2-tuple of (row,col)?

A dict maps keys to values. If your keys are coordinate pairs you can 
use this mapping like a 2-dimensional array. Example:

    d = {}
    d[1, 2] = 9     # store 9 at (1,2)
    d[3, 5] = 10    # store 10 at (3,5)

There are 2 caveats here:

Dict keys must be static hashable values. ints, float, strings fit this 
bill. So do tuples of such values, eg (1,2).

The other issue is what to do with the coordinates you have not set. For 
example, what happens if you access d[2,2] in the above code? There is 
no (2,2) entry, and a dict will raise a KeyError exception.

You have 2 main approaches to this: a defaultdict (presupplied in the 
standard library) or a dict subclass with a __missing__ method. The 
former will fill in entries as you access them - this is easy and 
convenient and I suggest you use it first. The latter need not fill in 
entries, but is more work to implement.

Using a defaultdict is like this:

    from collections import defaultdict
    .......
    d = defaultdict(int)
    d[1, 2] = 9     # store 9 at (1,2)
    d[3, 5] = 10    # store 10 at (3,5)

This is as before, but accessing an unfilled entry will fill it with the 
result of calling int(), which makes a 0. You can give defaultdict any 
callable which requires not arguments. For example "float", the float 
type, which will return 0.0 from floatz(). Or a small lambda if you want 
"None":

    d = defaultdict(lambda: None)

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Tutor mailing list