简体   繁体   中英

What is the Pythonic way to iterate over a dict of dicts and lists?

I have a dict which contains some lists and some dicts, as illustrated below.

What is the most pythonic way to iterate over the dict and print out the name and address pairs for each top level dict key?

Thanks

{
    'Resent-Bcc': [],
    'Delivered-To': [],
    'From': {'Name': 'Steve Watson', 'Address': 'steve.watson@example.org'},
    'Cc': [],
    'Resent-Cc': [],
    'Bcc': [ {'Name': 'Daryl Hurstbridge', 'Address': 'daryl.hurstbridge@example.org'},
             {'Name': 'Sally Hervorth', 'Address': 'sally.hervorth@example.org'},
             {'Name': 'Mike Merry', 'Address': 'mike.merry@example.org'},
             {'Name': 'Jenny Callisto', 'Address': 'jenny.callisto@example.org'}
           ],
    'To': {'Name': 'Darius Jedburgh', 'Address': 'darius.jedburgh@example.org'}
}

Use the iteritems() method on the dict. It's clear and easy to understand: that seems Pythonic to me. iteritems() also creates less temporary items than items() , as Preet Kukreti mentioned in the comments. First, fix your data. Right now, some of the values in the top-level dict are lists, and some are more dicts:

# list
'Delivered-To': [],
# dict
'From': {'Name': 'Steve Watson', 'Address': 'steve.watson@example.org'},

This means you have to check the type of the value and act accordingly (and you might forget to check!). Make your data consistent:

# list
'Delivered-To': [],
# also list
'From': [{'Name': 'Steve Watson', 'Address': 'steve.watson@example.org'}],

This will prevent weird type-related bugs in the future. Since Python is an interpreted language, it's very easy to make type bugs and not notice until your code is in production and crashes. Try to make your code as type-safe as possible!

Then you can use something like this:

for k, v in d.iteritems():
  for row in v:
    if "Name" in row and "Address" in row:
      print row["Name"], ":", row["Address"]

One way is to change the lone dicts into a list containing the dict. Then all the entries can be treated the same

>>> D = {
...     'Resent-Bcc': [],
...     'Delivered-To': [],
...     'From': {'Name': 'Steve Watson', 'Address': 'steve.watson@example.org'},
...     'Cc': [],
...     'Resent-Cc': [],
...     'Bcc': [ {'Name': 'Daryl Hurstbridge', 'Address': 'daryl.hurstbridge@example.org'},
...              {'Name': 'Sally Hervorth', 'Address': 'sally.hervorth@example.org'},
...              {'Name': 'Mike Merry', 'Address': 'mike.merry@example.org'},
...              {'Name': 'Jenny Callisto', 'Address': 'jenny.callisto@example.org'}
...            ],
...     'To': {'Name': 'Darius Jedburgh', 'Address': 'darius.jedburgh@example.org'}
... }
>>> L = [v if type(v) is list else [v] for v in D.values()]
>>> [(d["Name"], d["Address"]) for item in L for d in item ]
[('Steve Watson', 'steve.watson@example.org'), ('Daryl Hurstbridge', 'daryl.hurstbridge@example.org'), ('Sally Hervorth', 'sally.hervorth@example.org'), ('Mike Merry', 'mike.merry@example.org'), ('Jenny Callisto', 'jenny.callisto@example.org'), ('Darius Jedburgh', 'darius.jedburgh@example.org')]

Or the one liner version

[(d["Name"], d["Address"]) for item in (v if type(v) is list else [v] for v in D.values())]

It's probably best to keep your data simple, by making the naked dict's be a list of one element holding the original dict. Otherwise, you're kind of asking for harder to test code.

I tend to lean away from isinstance(foo, dict) and instead use things like: if getattr(d, 'iteritems'): print list(d.iteritems())

...It strikes me as more duck-typed this way; it opens the door to using one of the many dict-replacements - things that act like a dict, but nominally aren't a dict.

for key in header:
    if header[key] and type(header[key])==type([]):
        for item in header[key]:
            print (item)
    elif type(header[key])==type({}):
        print(header[key])

# this option is not the easiest to read, so I classify it as less "pythonic"       
l = [header[key] for key in header if header[key] and type(header[key])==type({})] + [header[key][i] for key in header if header[key] and type(header[key])==type([]) for i in range(len(header[key]))]
for item in l:
    print(item)

if you're looking for the contents of a specific header you could modify the if statements accordingly. Both of these examples print the dictionaries, but could easily be adapted to print specific values.

for i in dict:
   if 'Name' in dict[i]: 
      print (dict[i]['Name'],dict[i]['Address'])

this will not work for the bcc where its in a list (right now it will only print the from and to names and addresses) Do you need it to print the bcc addresses too?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM