我有一个名为“UserDatabaseRecord”的类。它有一堆字段,如“用户名”、“过期日期”等。
我有两个 UserDatabaseRecord 对象列表:列表 A 和列表 B
我想验证列表 A 中的所有 UserDatabaseRecords 的用户名字段都不匹配列表 B 中的任何 UserDatabaseRecords 用户名字段。
我能够非常低效地完成此任务:
for record_a in List_A:
for record_b in List_B:
if record_a.username == record_b.username:
print "Duplicate username: {0}".format(record_a.username)
我想,这行得通。我只是想让它更高效和/或“Pythonic”。
这个问题是相关的,但最终我无法弄清楚如何在仅比较一个字段时将其应用于对象列表:one-liner to check if at least one item in list exists in another list?
最佳答案
问题在于,对于列表 A 中的每个元素,您正在检查列表 B 中的所有元素。因此,如果您的列表的长度为 N 和 M,那就是 N*M 比较。
如果您从列表 B 中创建一组用户名,那么您只需在其上使用 in
运算符——这不仅更简单,而且是即时的,而不必检查所有的用户名一个一个的值。因此,您只需要 N 次查找而不是 N*M 次。
所以:
b_names = {record.username for record in List_B}
for record_a in List_A:
if record_a.username in b_names:
print "Duplicate username: {0}".format(record_a.username)
或者,更简单的,使用集合交集:
a_names = {record.username for record in List_A}
b_names = {record.username for record in List_B}
for name in a_names & b_names:
print "Duplicate username: {0}".format(name)
实际上,您不需要将它们都设为集合,您可以使用生成器表达式将一个设为集合,将另一个设为迭代器:
a_names = {record.username for record in List_A}
b_names = (record.username for record in List_B)
for name in a_names.intersection(b_names):
print "Duplicate username: {0}".format(name)
其中一个可能比其他的快一点,但它们都在同一个范围内——更重要的是,它们都是线性的而不是二次方的。因此,我建议您使用最适合您的一种。
如果你只需要知道是否有重复项而不是获取它们的列表,或者只需要任意获取一个重复项而不是所有重复项,你可以通过尽早“短路”来加快速度——例如,在第一个 print
之后添加一个 break
,或者在最后一个中使用 isdisjoint
而不是 intersection
一个。
关于Python 2.6 : How can I compare two lists of same object types on one particular field, 有效吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21345559/