循环多个具有多个值的生成器

时间:2018-10-19 19:27:22

标签: python python-3.x loops dictionary generator

我试图遍历两个给定字典的所有元素,以确保它们相等,如果不相等,我想要它们不同的属性的名称。

这是我的基本方法:

# Dictionnaries
v1 = { "a" : { "b" : 1, "c" : 2 }, "d" : { "e" : { "f" : 3 }}}
v2 = { "a" : { "b" : 1, "c" : 2 }, "d" : { "e" : { "f" : 4 }}}

def gen(k, v):
    if type(v) is dict:
        for k in v:
            yield from gen(k, v[k])
    else:
        yield k, v

# Used alone the generator works as expected:
for k, v in gen("root", v1):
    print("{}: {}".format(k, v))

我的问题是我想比较这两个字典,据我收集,它应该像这样:

for k1, v1, k2, v2 in zip(gen("root1", v1), gen("root2", v2)):
    print("{}: {}".format(k1, v1))
    print("{}: {}".format(k2, v2))
    print("===========")

解释器说只返回两个值,所以我认为这是可行的(确实如此):

for t1, t2 in zip(gen("root1", v1), gen("root2", v2)):
    print("{}: {}".format(t1[0], t1[1]))
    print("{}: {}".format(t2[0], t2[1]))
    print("===========")

我的问题:

这可能纯粹是优惠,但我真的很奇怪

  1. 如何使第一个循环生效,这样我就不必一直使用方括号了?
  2. 我尝试用*打开包装,但没有成功。为什么我不能zip(*gen(...), *gen(...))

(通过我知道可以在循环开始时添加k1, v1, k2, v2 = *t1, *t2的方式,我只是在寻找更好的解决方案)

2 个答案:

答案 0 :(得分:4)

您可以按照以下步骤打开每个返回的元组的包装:

for (k1, val1), (k2, val2) in zip(gen('root1', v1), gen('root2', v2)):
    ...

答案 1 :(得分:0)

您的问题更特定于语法,但是您可能需要考虑一些事项:

  1. 字典是无序集合,因此即使这些字典是相同的,也可能由于它们以不同顺序进行迭代而导致比较失败。
  2. Python没有Tail Call Optimization,因此对于足够嵌套的字典,该代码将因堆栈溢出而失败。

如果您想直观地比较字典,可以使用以下解决方案来解决这些问题。

假设:字典的结构是相同的(键是相同的,如果1的值是字典,则它将是另一个的字典,这些键不能是其他类型的可迭代对象,例如列表)。

from collections import deque

def gen(dct1, dct2):
    q = deque()
    q.append(("root", dct1, dct2))
    while q:
        k, d1, d2 = q.pop()
        for key in d1:  # assuming the same keys for both dicts
            val1 = d1[key]
            val2 = d2[key]

            # assuming that if the structure is the same -> if val1 is a dict, val2 is a dict as well 
            if isinstance(val1, dict): 
                q.append((k, val1, val2)) 
            else:
                yield key, val1, val2

for k, val1, val2 in gen(v1, v2):
    print("{}: {}".format(k, val1))
    print("{}: {}".format(k, val2))
    print("===========")