开发者

Pythonic way to parse list of dictionaries for a specific attribute?

I want to cross reference a dictionary and django queryset to determine which elements have unique dictionary['name'] and djangoModel.name values, respectively. The way I'm doing this now is to:

  • Create a list of the dictionary['name'] values
  • Create a list of djangoModel.name values
  • Generate the list of unique values by checking for inclusion in those lists

This looks as follows:

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]

It feels unpythonic to have to generate the intermediate list of names (lines 2 and 3 above), just to be able to check for inclusion immediately after. Am I missing anything? I suppose I could put two list comprehensions in one line like this:

obsoleteTests = [dbtest for dbtest in alldbTests if dbtest.name not in [vctest['name'] for vctest in vcdict['tests']]]

But that seems harder to follow.

Edit: Think of the initial state like this:

# vcdict is a list of d开发者_如何学运维jango 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]

I can't convert to sets and take the difference unless I strip things down to just the name string, but then I lose access to the rest of the model/dictionary, right? Sets only would work here if I had the same type of object in both cases.


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())]


You're working with basic set operations here. You could convert your objects to sets and just find the intersection (think Venn Diagrams):

obsoleteTests = list(set([a.name for a in alldbTests]) - set(vctestNames))

Sets are really useful when comparing two lists of objects (pseudopython):

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]


The intersection- and difference-operations of sets should help you solve your problem more elegant.

But as you're originally dealing with dicts these examples and discussion may provide some inspirations: http://code.activestate.com/recipes/59875-finding-the-intersection-of-two-dicts

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜