【问题标题】:What is the Pythonic way to iterate over a dict of dicts and lists?迭代字典和列表的字典的 Pythonic 方法是什么?
【发布时间】:2012-04-16 16:32:47
【问题描述】:

我有一个包含一些列表和一些字典的字典,如下图所示。

迭代字典并打印出每个顶级字典键的名称和地址对的最 Pythonic 方式是什么?

谢谢

{
    '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'}
}

【问题讨论】:

  • 我希望这些不是真实的电子邮件地址。
  • 不,我只是编造的。虽然我猜很多编造的 gmail 地址都是真实的。我对它们进行了编辑,使它们更加虚构,不再是 gmail。
  • 总是使用 example.org 或 example.com :)
  • 您是否在问如何均匀地迭代列表和字典?如,如果它是列表还是字典,您不想进行类型检查以分支?
  • 另外,您只需要顶级字典的名称和地址吗? “密送”中的那些呢?

标签: python dictionary


【解决方案1】:

在字典上使用iteritems() 方法。它清晰易懂:这对我来说似乎是 Pythonic。 iteritems() 也比 items() 创建的临时项目更少,正如 Preet Kukreti 在 cmets 中提到的那样。首先,修复您的数据。现在,顶级dict中的一些值是列表,有些是更多的dict:

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

这意味着您必须检查值的类型并采取相应措施(您可能会忘记检查!)。使您的数据保持一致:

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

这将防止将来出现奇怪的类型相关错误。由于 Python 是一种解释性语言,因此很容易产生类型错误,并且在您的代码投入生产并崩溃之前不会注意到。尽量让你的代码类型安全!

然后你可以使用这样的东西:

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

【讨论】:

  • 赞成但更喜欢.iteritems()。它比.items() 更高效,因为items() 创建了更多的临时对象。
  • 你已经回答了我的问题。我试图了解是否有一种平滑的方式来处理顶级字典包含列表和字典的混合这一事实。您似乎在暗示没有,并且应该更改顶级数组以更加一致。我希望避免这种情况。
  • @DukeDougal 最流畅的方式是 gnibbler 发布的内容:检查对象的类型并采取相应措施。
  • @DukeDougal 是的,最好的方法是实际编写一个生成器函数,该函数返回一个生成器对象(可迭代),它在不创建本地副本的情况下提供数据的同质“视图”。这是通过type()isinstance 在内部完成的,然后转换并yielded 作为目标同质类型(例如dictlist),因此您可以迭代非同质“视图”同质集合。您也可以通过列表理解 ((..)) 的元组/生成器变体或 lambda 函数来执行此操作。
  • @preetKukreti 是否有机会提供代码片段来说明您的建议?谢谢
【解决方案2】:

一种方法是将单独的字典更改为包含该字典的列表。然后所有条目都可以被视为相同

>>> 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')]

或单排版

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

【讨论】:

  • 我认为你应该使用isinstance 而不是typeis
  • @Kris,当对象可能是列表的子类时,isinstance 是合适的。我认为在这种情况下不太可能
  • @gnibbler 当对象完全是列表而不是子类时,您认为isinstance 不合适吗? (例如,我可以在这里很容易地看到元组……)
  • @gnibbler isinstance 总是比对type 的相等检查要好。 isinstance 将起作用的情况是type 平等检查将起作用的情况的超集。并不是说这两种技术都很好,但isinstance“不那么糟糕”,应该是首选。
  • @kojiro,这是一个不同的问题,因为元组是一个序列,但不是列表的子类。所以你可以说isinstance(v, (list, tuple)),但如果你知道它永远是一个列表,那只会增加不必要的复杂性。
【解决方案3】:

最好让你的数据保持简单,让裸字典成为一个包含原始字典的元素的列表。否则,您会要求更难测试代码。

我倾向于远离 isinstance(foo, dict) 而是使用以下内容: if getattr(d, 'iteritems'): 打印列表(d.iteritems())

...我觉得这种方式更像鸭子类型;它为使用许多 dict-replacements 之一打开了大门 - 行为类似于 dict,但名义上不是 dict 的东西。

【讨论】:

    【解决方案4】:
    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 语句。这两个示例都打印字典,但可以很容易地调整为打印特定值。

    【讨论】:

      【解决方案5】:
      for i in dict:
         if 'Name' in dict[i]: 
            print (dict[i]['Name'],dict[i]['Address'])
      

      这不适用于列表中的密件抄送(现在它只会打印发件人姓名和地址)您也需要它来打印密件抄送地址吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-15
        • 1970-01-01
        • 2016-02-13
        • 2012-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多