views:

63

answers:

3

I have a nested list something like this:

PLACES = (
    ('CA', 'Canada', (
        ('AB', 'Alberta'),
        ('BC', 'British Columbia' (
            ('van', 'Vancouver'),
        ),
        ...
    )),
    ('US', 'United States', (
        ('AL', 'Alabama'),
        ('AK', 'Alaska'),
        ...

I need to retrieve some data out of it. If depth is 0 I need to retrieve all the countries (and their codes), if depth == 1, I need to retrieve all the states/provinces, if depth == 2 I need to retrieve all the cities... and so forth. Is there some set library for doing stuff like this? Or can someone point me in the right direction? I started coding up a solution only to realize it wouldn't work for levels deeper than 1 because you have to go in and out of each list...

Also notice that not all items have a 3rd part (i.e., we're pretending Alberta doesn't have any cities, so retrieving items at depth 2 would just return ('van','Vancouver') in this limited scenario).


I didn't realize this before, but I also needed the parent value. So, I modified interjay's solution:

def depth_gen(seq, depth, par=None):
    if depth==0:
        for x in seq:
            yield par, x[0], x[1] 
        return

    for x in seq:
        if len(x)==3:
            par = x[0]
            for y in depth_gen(x[2], depth-1, par):
                yield y

Which I'm using to generate some HTML:

<label for="id-pickup_address-province">Province</label>
<select id="id-pickup_address-province" rel="pickup_address-country" name="pickup_address-province">
    <option rel="CA" value="AB">Alberta</option>
    <option rel="CA" value="BC">British Columbia</option>
    <option rel="CA" value="MB">Manitoba</option>
    ...
    <option rel="US" value="WV">West Virginia</option>
    <option rel="US" value="WI">Wisconsin</option>
    <option rel="US" value="WY">Wyoming</option>
</select>
<label for="id-pickup_address-country">Country</label>
<select id="id-pickup_address-country" name="pickup_address-country">
    <option value="CA">Canada</option>
    <option value="US">United States</option>
</select>

And then I should be able to easily filter the list with jQuery based on which country is selected...

+1  A: 

This is what I see:

for (county, countryName, stateTuple) in MyTuple:
     for (state, stateName, CountyTuple) in stateTuple:
         ...

and so on, which is a repeating pattern.

def extract( myTuple, level ):
    if level:
        return ( item[2] for item in myTuple if len(item) == 3)
    else:
        return ( (item[0], item[1]) for item in myTuple )

Then call extract as many times as you need for your "depth".

wheaties
+1  A: 

Suggestion, don't use nested lists. Create some kind of real structure of classes that gives you more information and organization. It will make it easier to think about, easier to code and easier for other people to read.

unholysampler
I'm going for ease of creation. This is going into a framework, and I want people to be able to write out their choices quickly without any extra fluff.
Mark
(Thanks for the suggestion though!)
Mark
+4  A: 

Here is a solution which will work for any depth:

def depthGenerator(seq, depth):
    if depth==0:
        for x in seq:
            yield x[:2] #strip subsequences
        return

    for x in seq:
        if len(x)==3:   #has subsequence?
            for y in depthGenerator(x[2], depth-1):
                yield y

Example:

>>> list(depthGenerator(PLACES, 1))
[('AB', 'Alberta'), ('BC', 'British Columbia'), ('AL', 'Alabama'), ('AK', 'Alaska')]
interjay
This looks way more elegant and functional than what I was working on !
Mark