[Tutor] SubDictionaries or am I reinventing a wheel?

Roeland Rengelink r.b.rigilink@chello.nl
Tue, 12 Jun 2001 14:23:29 +0200


"Patrick K. O'Brien" wrote:


Hi Patrick,

> 
> Imagine that you have a dictionary with a multipart key and you want to
> extract a new dictionary that is a subset of the existing dictionary based
> on matching a few of the leading elements that make up the key. For example,
> GoldMine stores multiple record types in some of its database files. So I
> have a dictionary with the table name and record type code as the key.
> 
> gmRecordTypes = {  # Table, Type, Description
>     ('CAL', 'A'): 'Appointment',

<snip>

>     }
> 

Have you considered using nested dictionaries for this, i.e.:

gmRecordTypes = {'CAL': {'A': 'Appointment',
                         'C': 'Call back',
                         ...
                         'T': 'Next action},
                 'CONTHIST': {'A':'Appointment',
                              'C': 'Call back',
                              ...
                              'T': 'Next action'}}

You can then get at the subdictionaries through

subd = gmRecordTypes['CAL']

and individual values with

val = gmRecordTypes['CAL']['A']

This is sort of the standard approach for what you seem to describe.

> Now let's say I wanted a function that would return a new dictionary of just
> the record types and descriptions for the CONTHIST table. Think of this as
> sort of a query against a database table - select type, description from
> gmRecordTypes where table = 'CONTHIST'. Imagine that you had lots of
> dictionaries like this and that you wanted the function to be able to select
> based on one matching element or several matching elements of the key. Well,
> I did and here is what I came up with.
> 
> # partmatch can be a single value or any valid sequence for a dictionary key
> or portion thereof.
> 
> def subDictionary(dictionary, partmatch=None):
>     """Return a subset of a dictionary based on a partial key match."""
>     if partmatch == None:
>         return dictionary

Are you sure that subDictionary(dictionary) should return dictionary
itself,
while subDictionary(dictionary, ()) should return a copy?

>     else:
>         subd = {}
>         partsize = len(partmatch)
>         if partsize == 1:  # Reduce single element sequences to single
> elements.
>             partmatch = partmatch[0]
>         for key in dictionary.keys():
>             if partsize == 1:  # Reduce single element sequences to single
> elements.
>                 keypart = key[0]
>             else:
>                 keypart = key[:partsize]
>             if keypart == partmatch:
>                 if len(key[partsize:]) == 1:  # Simplify the new key by
> reducing it to a single object if possible.
>                     newkey = key[partsize]
>                 else:
>                     newkey = key[partsize:]
>                 subd[newkey] = dictionary[key]
>         return subd
> 

Here's my somewhat more concise version.
Note that I also test if key and partmatch are of the same type.

def subDictionary(dictionary, partmatch=()):
    """Return a subset of a dictionary based on a partial key match."""

    subd = {}
    for key, val in dictionary.items():
        if partial_match(partmatch, key):
            newkey = key[len(partmatch):]
            if len(newkey) == 1:
                newkey = newkey[0]
            subd[newkey] = val
    return subd

def partial_match(first, second):
    '''Match two sequences

    returns 0 if type(first) != type(second)
    
    returns 1 if second[:len(first)] == first
    returns 0 otherwise
    '''
    if type(first) != type(second):
        return 0
    return second[:len(first)] == first


> Now, I either came up with something nifty that will be useful to me and
> maybe others, or I just spent a good couple of hours reinventing the wheel.
> Does anyone know of any Python module that does this already? Is this a good
> approach to the problem I described, or am I off my rocker? 

Hey, your code works, which is the only practical definition of 'good
approach'

> Somehow this
> sort of manipulation seems like it should be part of the core of python in
> the way that keys() and values() are already there.
> 

This sounds like a nasty question, but think of it a an exercise.

Exactly what kind of manipulation do you mean? Remember keys() and
values() can be described exactly in one sentence only. Try to find the
one-sentence description for your proposed extensions. You could then
try building your own UserDict class that implements these manipulations
as additional methods.

Hope this helps,

Roeland

-- 
r.b.rigilink@chello.nl

"Half of what I say is nonsense. Unfortunately I don't know which half"