Сравнение списков словарей - PullRequest
5 голосов
/ 29 января 2012

У меня есть два списка результатов испытаний.Результаты теста представлены в виде словарей:

list1 = [{testclass='classname', testname='testname', testtime='...},...]
list2 = [{testclass='classname', testname='testname', ...},...]

Представление в словаре немного отличается в обоих списках, потому что для одного списка у меня есть немного больше информации.Но во всех случаях каждый тестовый словарь в любом списке будет иметь элемент classname и testname, которые вместе эффективно образуют способ уникальной идентификации теста и способ его сравнения по спискам.

Мне нужно выяснить всетесты, которые есть в списке list1, но не в списке list2, так как они представляют новые ошибки теста.

Для этого я делаю:

def get_new_failures(list1, list2):
    new_failures = []
    for test1 in list1:
        for test2 in list2:
            if test1['classname'] == test2['classname'] and \
                    test1['testname'] == test2['testname']:
                break; # Not new breakout of inner loop
        # Doesn't match anything must be new
        new_failures.append(test1);
    return new_failures;

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

Любая помощь будет оценена,

Спасибо.

Ответы [ 3 ]

8 голосов
/ 29 января 2012

Попробуйте это:

def get_new_failures(list1, list2):
    check = set([(d['classname'], d['testname']) for d in list2])
    return [d for d in list1 if (d['classname'], d['testname']) not in check]
2 голосов
/ 29 января 2012

Чтобы сравнить два dict d1 и d2 на подмножестве их клавиш, используйте:

all(d1[k] == d2[k] for k in ('testclass', 'testname'))

И если ваш список имеет одинаковую длину, вы можете использовать zip() для их сопряжения.

2 голосов
/ 29 января 2012

Если каждая комбинация classname и testname действительно уникальна, то более вычислительно эффективный подход будет состоять в использовании двух словарей вместо двух списков. В качестве ключа к словарю используйте кортеж так: (classname, testname). Тогда вы можете просто сказать if (classname, testname) in d: ....

Если вам нужно сохранить порядок вставки и вы используете Python 2.7 или выше, вы можете использовать OrderedDict из модуля collections.

Код будет выглядеть примерно так:

tests1 = {('classname', 'testname'):{'testclass':'classname', 
                                     'testname':'testname',...}, 
         ...}
tests2 = {('classname', 'testname'):{'testclass':'classname', 
                                     'testname':'testname',...}, 
         ...}

new_failures = [t for t in tests1 if t not in tests2]

Если вам по какой-то причине необходимо использовать списки, вы можете перебрать list2 для генерации набора, а затем проверить его на принадлежность к этому набору:

test1_tuples = ((d['classname'], d['testname']) for d in test1)
test2_tuples = set((d['classname'], d['testname']) for d in test2)
new_failures = [t for t in test1_tuples if t not in test2_tuples]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...