【问题标题】:Solving nested dict iteration by list comprehension or any other method通过列表理解或任何其他方法解决嵌套 dict 迭代
【发布时间】:2014-07-18 18:42:28
【问题描述】:

我有一个dict,其中包含另一个dict

d1 = {'a':{'p':1, 'q':2, 'r':'abc'}, 
      'b':{'p':5, 'q':6, 'r':["google", "pypi.org"]}
     }
url1 = "https://google.com"
url2 = "https://abc.com"

现在我想做的是从dict values 中检查r 的值,但我不想要任何代码冗余。这怎么可能?

我现在正在做的是:-

for k, v in d1.iteritems():
    if isinstance(v['r'], list):
        for l in v['r']:
            if url1.find(l):
                ..Do something..
            else:
                continue
    else:
        if url1.find(v['r'):
                ..Do Something same as above..
            else:
                continue

现在问题出现在相同的Do something重复2次,有没有办法解决冗余用理解或任何其他方法,除了函数制作和调用 .

编辑——代码已经在一个大的函数定义中,所以除了创建另一个函数并调用它之外,请提供其他解决方案。

【问题讨论】:

  • 这就是发明函数的目的。只需像 def do_something(): ..Do something.. 那样包装 ..Do something..。我不明白except function 部分。
  • @freakish- 问题是下面的代码已经在一个函数中并且它正在返回一些东西
  • 所以?您可以在函数内部定义函数(如有必要,例如,如果 do something 取决于上下文)然后调用它们。它是 Python。
  • @freakish- 函数会变慢,这是我不想要的,请提供除制作函数之外的解决方案。
  • 什么?那么慢呢?创建和调用函数的开销可以忽略不计。这种微优化只是浪费时间。您在这里有一个优雅的解决方案。

标签: python dictionary dictionary-comprehension


【解决方案1】:

您可以转换非列表项,即。在这种情况下将字符串添加到列表中,然后简单地遍历该列表。而且你不需要else: continue 部分:

for k, v in d1.iteritems():
    value = v['r'] if isinstance(v['r'], list) else [v['r']]
    for l in value:
        if url1.find(l):
           #Do something..

【讨论】:

    【解决方案2】:

    如果您非常重视 python 代码的性能并且愿意接受某些风格上的妥协,那么假设您使用pypy,以下表单的运行速度将与手动内联代码一样快:

    def inner():
        pass
    
    for k, v in d1.items():
        if isinstance(v['r'], list):
            for l in v['r']:
                if url1.find(l):
                    inner()
                else:
                    continue
        else:
            if url1.find(v['r']):
                inner()
            else:
                continue
    

    更真实的例子,包括非空内部和一些计时代码,请参阅this link.

    请注意,正如您所写,此版本比 CPython 下的内联版本慢得多,后者当然没有 JIT 内联。

    【讨论】:

      【解决方案3】:

      Freakish 是对的。使用函数将是这里的最佳解决方案。使用函数调用的开销可以忽略不计,而且可能比创建新列表和循环长度为 1 的列表要少。

      但是,如果您确实想不惜一切代价避免代码重复并避免多次函数调用,您可能需要考虑将代码重写为生成器函数。这将产生您想要一次处理一个的项目。

      def loop(d1):
          for k, v in d1.iteritems():
              if isinstance(v['r'], list):
                  for l in v['r']:
                      if url1.find(l):
                          yield l
                      else:
                          continue
              else:
                  if url1.find(v['r']):
                      yield v['r']
                  else:
                      continue
      
      for item in loop(d1):
          print "do something"
      

      【讨论】:

      • 这是一个更好的选择,但我不想创建另一个函数,因为代码已经在一个更大的函数中。
      • 您可以创建嵌套或顶级函数。它只会被调用一次(而不是像怪胎的建议那样每次循环迭代一次)。
      • @AyushTiwari 如果您不想创建另一个函数,那么复制代码并成为一个糟糕的编码器。你似乎不明白函数的用途。
      • @HansThen 我从来没有建议每次循环迭代都这样做一次。我说过要在大函数内部执行此操作,但要在循环之前。否则没有任何意义。顺便说一句:生成器只是“创建函数”的另一个词。它确实在后台创建函数并调用它们(即__iter__)。
      • 对不起,我以为您建议将“做某事”放在函数定义中,而不是执行“做某事”来调用该函数?这不是意味着每次循环迭代调用一个函数吗?
      猜你喜欢
      • 1970-01-01
      • 2021-06-18
      • 2021-06-20
      • 2015-12-07
      • 2018-01-11
      • 1970-01-01
      • 1970-01-01
      • 2015-10-25
      • 1970-01-01
      相关资源
      最近更新 更多