比较字典列表

5 投票
3 回答
4670 浏览
提问于 2025-04-17 11:53

我有两个测试结果的列表。这些测试结果用字典来表示:

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

这两个列表中的字典表示方式稍微有点不同,因为其中一个列表包含更多的信息。不过在所有情况下,每个测试字典都会有一个classname和一个testname,这两个元素结合起来可以唯一识别这个测试,并且可以用来在两个列表之间进行比较。

我需要找出在列表1中但不在列表2中的所有测试,因为这些测试代表了新的失败。

为此,我这样做:

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;

我在想有没有更符合Python风格的方法来实现这个。 我看过过滤器。过滤器使用的函数需要同时访问两个列表。一个列表很简单,但我不太确定怎么才能同时访问到两个列表。我知道列表的内容直到运行时才会确定。

任何帮助都将不胜感激,

谢谢。

3 个回答

2

如果每个 classnametestname 的组合都是独一无二的,那么更高效的方法是用两个字典,而不是两个列表。你可以把 (classname, testname) 作为字典的键。这样你就可以简单地用 if (classname, testname) in d: ... 来检查了。

如果你需要保持插入的顺序,并且使用的是 Python 2.7 或更高版本,你可以使用 collections 模块里的 OrderedDict

代码大概是这样的:

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]
2

要比较两个字典 d1d2 中某些特定的键,可以使用:

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

如果你的两个列表长度相同,可以使用 zip() 来把它们配对起来。

8

试试这个:

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]

撰写回答