以Pythonic方式解析字典列表中特定属性?
我想要对比一个字典和Django的查询集,看看哪些元素在各自的dictionary['name']
和djangoModel.name
中是独一无二的。现在我做法是:
- 先创建一个包含字典中所有
dictionary['name']
值的列表 - 再创建一个包含
djangoModel.name
值的列表 - 通过检查这些列表来生成唯一值的列表
这个过程看起来是这样的:
alldbTests = dbp.test_set.exclude(end_date__isnull=False) #django queryset
vctestNames = [vctest['name'] for vctest in vcdict['tests']] #from dictionary
dbtestNames = [dbtest.name for dbtest in alldbTests] #from django model
# Compare tests in protocol in fortytwo's db with protocol from vc
obsoleteTests = [dbtest for dbtest in alldbTests if dbtest.name not in vctestNames]
newTests = [vctest for vctest in vcdict if vctest['name'] not in dbtestNames]
我觉得这样生成中间的名字列表(上面第2和第3行)有点不太符合Python的风格,因为我只是为了能马上检查包含关系。难道我漏掉了什么吗?我想我可以把两个列表推导放在一行里,像这样:
obsoleteTests = [dbtest for dbtest in alldbTests if dbtest.name not in [vctest['name'] for vctest in vcdict['tests']]]
但这样似乎更难理解。
编辑:想象一下最初的状态是这样的:
# vcdict is a list of django models where the following are all true
alldBTests[0].name == 'test1'
alldBTests[1].name == 'test2'
alldBTests[2].name == 'test4'
dict1 = {'name':'test1', 'status':'pass'}
dict2 = {'name':'test2', 'status':'pass'}
dict3 = {'name':'test5', 'status':'fail'}
vcdict = [dict1, dict2, dict3]
我不能直接转换成集合并取差集,除非我只保留名字字符串,但那样我就无法访问模型或字典的其他部分,对吧?只有在两者都是同类型对象的情况下,集合才适用。
3 个回答
集合的 intersection
(交集)和 difference
(差集)操作可以帮助你更优雅地解决问题。
不过因为你最开始是在处理字典,这些例子和讨论可能会给你一些启发:http://code.activestate.com/recipes/59875-finding-the-intersection-of-two-dicts
你在这里处理的是基本的集合操作。你可以把你的对象转换成集合,然后找到它们的交集(可以想象成维恩图):
obsoleteTests = list(set([a.name for a in alldbTests]) - set(vctestNames))
集合在比较两个对象列表时非常有用(伪Python代码):
set(a) - set(b) = [c for c in a and not in b]
set(a) + set(b) = [c for c in a or in b]
set(a).intersection(set(b)) = [c for c in a and in b]
在编程中,有时候我们需要处理一些数据,比如从一个地方获取数据,然后把它放到另一个地方。这就像是把书从一个书架搬到另一个书架一样。
有些时候,我们会遇到一些问题,比如数据格式不对,或者数据丢失了。这就像是你搬书的时候,发现有些书掉了,或者书的封面被撕坏了。
为了避免这些问题,我们可以使用一些工具或者方法来帮助我们。比如,我们可以检查数据的完整性,确保所有的数据都在,而且格式是正确的。这样就能减少出错的机会。
总之,处理数据就像搬家一样,需要小心翼翼,确保每一件东西都能安全到达目的地。
vctestNames = dict((vctest['name'], vctest) for vctest in vcdict['tests'])
dbtestNames = dict((dbtest.name, dbtest) for dbtest in alldbTests)
obsoleteTests = [vctestNames[key]
for key in set(vctestNames.keys()) - set(dbtestNames.keys())]
newTests = [dbtestNames[key]
for key in set(dbtestNames.keys()) - set(vctestNames.keys())]