Цикл по нескольким генераторам нескольких значений - PullRequest
0 голосов
/ 19 октября 2018

Я пытаюсь просмотреть все элементы двух данных словарей, чтобы убедиться, что они равны, и если нет, я хочу назвать свойство, в котором они различаются.

Вот мой основной подход:

# 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 голосов
/ 20 октября 2018

Ваш вопрос был более специфичен для синтаксиса, но есть некоторые вещи, которые вы могли бы рассмотреть:

  1. словари являются неупорядоченными коллекциями, поэтому сравнение может потерпеть неудачу, даже если эти слова совпадают только потому, что онибыли перебраны в другом порядке.
  2. Python не имеет Оптимизация вызовов Tail , поэтому для достаточно вложенных кодов этот код завершится ошибкой с переполнением стека.

Если вы хотите визуально сравнить диктанты, вот решение, которое решает эти проблемы.

Предположение: структура диктов одинакова (ключи одинаковы, если значение для 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("===========")
0 голосов
/ 19 октября 2018

Вы можете распаковать каждый возвращенный кортеж следующим образом:

for (k1, val1), (k2, val2) in zip(gen('root1', v1), gen('root2', v2)):
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...