Comparing multiple dictionaries in Python

I am new to Python, and I am running into a problem due to which I cannot exit Google. I created a GUI using wxPython and ObjectiveListView. At the very center, the GUI has a list control that displays data in X-lines (data loaded by the user) and in five columns.

When the user selects several entries from the list control (CTRL or shift while pressing), the ObjectiveListView module provides me with a list of dictionaries, dictionaries containing the data in the lines of the list control. This is exactly what I want, alright!

The returned list looks something like this:

print MyList [{'id':1023, 'type':'Purchase', 'date':'23.8.2008', 'sum':'-21,90', 'target':'Apple Store'}, {'id':1024, 'type':'Purchase', 'date':'24.8.2008', 'sum':'-21,90', 'target':'Apple Store'}, {'id':23, 'type':'Purchase', 'date':'2.8.2008', 'sum':'-21,90', 'target':'Apple Store'}] 

All dictionaries have the same keys, but the values โ€‹โ€‹change. The value of "id" is unique. This is where the problems begin. I want to get common values โ€‹โ€‹for all elements selected by the user. In the above list, they will be "sum": "21.90" and "target": "Apple Store".

I do not know how to compare dicts in a list correctly. One of the big problems is that I donโ€™t know in advance how many dictation lists contain, as it is user defined.

I have a vague idea that understanding lists will be a way, but I only know how to compare two lists with a list, not n lists. Any help would be appreciated.

+4
source share
5 answers
 >>> mysets = (set(x.items()) for x in MyList) >>> reduce(lambda a,b: a.intersection(b), mysets) set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')]) 

First, I created a generator that converts a list of dicts into an iterable sequence of sets of key pairs, values. You can use list comprehension here, but this method does not convert your entire list into another list, useful if you donโ€™t know how big it will be.

Then I used a shorthand to apply a function that finds common values โ€‹โ€‹between each set. He finds the intersection of set 1 and set 2, which is itself a set, then the intersection of this set and set 3, etc. The mysets generator will happily serve each set as required by the reduction function until it is complete.

I believe the shortcut was deprecated as built-in in Python 3.0, but should still be available in functools.

Of course, you could make it one liner, replacing the mysets in the abbreviation with the expression of the generator, but this will reduce the readability of the IMO. In practice, I will probably even take one more step and break the lambda in my line:

 >>> mysets = (set(x.items()) for x in MyList) >>> find_common = lambda a,b: a.intersection(b) >>> reduce(find_common, mysets) set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')]) 

And if you want the end result to be a dict, just wrap it like this:

 >>> dict(reduce(find_common, mysets)) {'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'} 

dict can accept any iterator of keys, pairs of values, for example, a set of tuples returned at the end.

+7
source

My answer is identical to Matthew Trevor, except for one difference:

 >>> mysets = (set(x.items()) for x in MyList) >>> reduce(set.intersection, mysets) set([('sum', '-21,90'), ('type', 'Purchase'), ('target', 'Apple Store')]) 

Here I use set.intersection instead of creating a new lambda. In my opinion, this is more readable, as it intuitively reads as "shrinking reduces this list with the given intersection operator." It should also be much faster since set.intersection is a C built-in function.

To fully answer your question, you can extract the values โ€‹โ€‹using a list comprehension:

 >>> mysets = (set(x.items()) for x in MyList) >>> result = reduce(set.intersection, mysets) >>> values = [r[1] for r in result] >>> values ['-21,90', 'Purchase', 'Apple Store'] 

This will end for me in one line. but it is entirely up to you:

 >>> [r[1] for r in reduce(set.intersection, (set(x.items()) for x in myList))] ['-21,90', 'Purchase', 'Apple Store'] 
+7
source

First we need a function to calculate the intersection of two dictionaries:

 def IntersectDicts( d1, d2 ) : return dict(filter(lambda (k,v) : k in d2 and d2[k] == v, d1.items())) 

Then we can use it to process any number of dictionaries:

 result = reduce(IntersectDicts, MyList) 
+2
source

Since you are only looking for a generic set, you can compare keys in the first dictionary with keys in all other dictionaries:

 common = {} for k in MyList[0]: for i in xrange(1,len(MyList)): if MyList[0][k] != MyList[i][k]: continue common[k] = MyList[0][k] >>> common {'sum': '-21,90', 'type': 'Purchase', 'target': 'Apple Store'} 
+1
source

Sorry, yes, "type": "Purchasing" is also one of the common meanings. You had to log in to change the question.

0
source

All Articles