[Tutor] 3 Dimensional Dictionaries

Steven D'Aprano steve at pearwood.info
Sat Jul 20 18:17:05 CEST 2013


On 20/07/13 20:17, Sunil Tech wrote:
> Hi Everyone,
>
> I have a list of dictionaries like


Hi Sunil,


A couple of style issues here.

Please put spaces between parts of your code, for two reasons. Firstly, it makes it a lot easier to read, or perhaps I should say, notusingspacesmakesitmuchhardertoread.

Secondly, when you don't use spaces, it's much harder for the email program to word-wrap lines, and your readers have to do a lot more work to read your email in detail. Since we're volunteers, and not being paid to answer your questions, you should make it as simple as possible for us. If you make it hard to understand your question, we simply might not bother.

As far as your actual question, I'm not sure how we can answer it. You already know how to turn the list of dictionaries into a list of nested dictionaries and lists, because you did it yourself. Write down the steps you did, in English (or the human language of your choice), then turn each step into Python code.

As your question stands right now, I'm not even sure I understand what process you used to merge the list-of-dicts into a different list-of-dicts. But I can see one thing: the continent code is unused, so I have deleted it from your examples to make it easier to read.

Your data currently looks like this:

old_world = [
     {'continent': 'Asia', 'ocean': 'Pacific', 'country': 'India',
      'country_code': 1, 'state': 'Kerala', 'state_pin': 500001},
     {'continent': 'Asia', 'ocean': 'Pacific', 'country': 'India',
      'country_code': 1, 'state': 'Karnataka', 'state_pin': 500002},
     {'continent': 'Africa', 'ocean': 'Atlantic', 'country': 'Egypt',
      'country_code': 2, 'state': 'East Egypt', 'state_pin': 700001},
     {'continent': 'Africa', 'ocean': 'Atlantic', 'country': 'Egypt',
      'country_code': 2, 'state': 'West Egypt', 'state_pin': 700002},
     {'continent': 'Africa', 'ocean': 'Atlantic', 'country': 'Egypt',
      'country_code': 2, 'state': 'North Egypt', 'state_pin': 700003},
     ]


(By the way, Egypt is nowhere near the Atlantic.)



And you want to collect it in the form:


world = [
     {'continent': 'Asia', 'ocean': 'Pacific',
      'countries':
          [{'country': 'India',
            'states': [{'state': 'Kerala', 'state_pin': 500001},
                       {'state': 'Karnataka', 'state_pin': 500002}
                      ]
           }
          ]
     },
     {'continent': 'Africa', 'ocean': 'Atlantic',
      'countries':
          [{'country': 'Egypt',
            'states': [{'state': 'East Egypt', 'state_pin': 700001},
                       {'state': 'West Egypt', 'state_pin': 700002},
                       {'state': 'North Egypt', 'state_pin': 700003}
                      ]
           }
          ]
     }
]


In my opinion, that is a horrible design for a data structure. XML has got a *lot* to answer for. (Actually, XML is not the problem. XML is fine for what it is designed for, which is transferring data from one application to another. What is the problem is languages and programmers who try to use XML, and XML-inspired designs, for their internal data structures.)


Anyway, I think we can improve it by using a few helpful data structures, and smarter use of dictionaries:


from collections import namedtuple
Continent = namedtuple("Continent", "ocean countries")
State = namedtuple("State", "state pin")


world = {}  # hold the new data
for d in old_world:
     continent = d['continent']
     if continent not in world:
         world[continent] = Continent(d['ocean'], {})
     country = d['country']
     if country not in world[continent].countries:
         world[continent].countries[country] = []
     state = State(d['state'], d['state_pin'])
     world[continent].countries[country].append(state)

print(world)


which gives this data structure:

{'Asia':
       Continent(ocean='Pacific',
         countries={
           'India': [State(state='Kerala', pin=500001),
                     State(state='Karnataka', pin=500002)
                    ]
                   }
                ),
  'Africa':
       Continent(ocean='Atlantic',
         countries={
           'Egypt': [State(state='East Egypt', pin=700001),
                     State(state='West Egypt', pin=700002),
                     State(state='North Egypt', pin=700003)
                    ]
                   }
                )
}


(Disclaimer: I manually pretty-printed the above. When Python prints it, it doesn't look anywhere nearly so good.)

I realise that this is not exactly what you asked for, but in my opinion this is a better data structure than what you suggested. If you disagree, you should be able to modify my code to do what you prefer, the basic style will be the same.

Good luck!


-- 
Steven


More information about the Tutor mailing list