How to compare two lists of dicts in Python?
Question: How do I compare two lists of `dict`? The result should be the odd ones out
from the list of dict B.

Example:

    
    
    ldA = [{'user':"nameA", 'a':7.6, 'b':100.0, 'c':45.5, 'd':48.9},
           {'user':"nameB", 'a':46.7, 'b':67.3, 'c':0.0, 'd':5.5}]
    
    
    ldB =[{'user':"nameA", 'a':7.6, 'b':99.9, 'c':45.5, 'd':43.7},
          {'user':"nameB", 'a':67.7, 'b':67.3, 'c':1.1, 'd':5.5},
          {'user':"nameC", 'a':89.9, 'b':77.3, 'c':2.2, 'd':6.5}]
    

Here I want to compare ldA with ldB. It should print the below output.

    
    
    ldB -> {user:"nameA",  b:99.9, d:43.7}
    ldB -> {user:"nameB",  a:67.7, c:1.1 }
    ldb -> {user:"nameC", a:89.9, b:77.3, c:2.2, d:6.5}
    

I have gone through the below link, but there it return onlys the name, but I
want name and value like above.

_[List of Dicts comparision to match between lists and detect value changes in
Python](http://stackoverflow.com/questions/2412562/list-of-dicts-comparision-
to-match-between-lists-and-detect-value-change-in-pytho)_


Answer: For a general solution, consider the following. It will properly diff, even if
the users are out of order in the lists.

    
    
    def dict_diff ( merge, lhs, rhs ):
        """Generic dictionary difference."""
        diff = {}
        for key in lhs.keys():
              # auto-merge for missing key on right-hand-side.
            if (not rhs.has_key(key)):
                diff[key] = lhs[key]
              # on collision, invoke custom merge function.
            elif (lhs[key] != rhs[key]):
                diff[key] = merge(lhs[key], rhs[key])
        for key in rhs.keys():
              # auto-merge for missing key on left-hand-side.
            if (not lhs.has_key(key)):
                diff[key] = rhs[key]
        return diff
    
    def user_diff ( lhs, rhs ):
        """Merge dictionaries using value from right-hand-side on conflict."""
        merge = lambda l,r: r
        return dict_diff(merge, lhs, rhs)
    
    import copy
    
    def push ( x, k, v ):
        """Returns copy of dict `x` with key `k` set to `v`."""
        x = copy.copy(x); x[k] = v; return x
    
    def pop ( x, k ):
        """Returns copy of dict `x` without key `k`."""
        x = copy.copy(x); del x[k]; return x
    
    def special_diff ( lhs, rhs, k ):
          # transform list of dicts into 2 levels of dicts, 1st level index by k.
        lhs = dict([(D[k],pop(D,k)) for D in lhs])
        rhs = dict([(D[k],pop(D,k)) for D in rhs])
          # diff at the 1st level.
        c = dict_diff(user_diff, lhs, rhs)
          # transform to back to initial format.
        return [push(D,k,K) for (K,D) in c.items()]
    

Then, you can check the solution:

    
    
    ldA = [{'user':"nameA", 'a':7.6, 'b':100.0, 'c':45.5, 'd':48.9},
           {'user':"nameB", 'a':46.7, 'b':67.3, 'c':0.0, 'd':5.5}]
    ldB =[{'user':"nameA", 'a':7.6, 'b':99.9, 'c':45.5, 'd':43.7},
          {'user':"nameB", 'a':67.7, 'b':67.3, 'c':1.1, 'd':5.5},
          {'user':"nameC", 'a':89.9, 'b':77.3, 'c':2.2, 'd':6.5}]
    import pprint
    if __name__ == '__main__':
        pprint.pprint(special_diff(ldA, ldB, 'user'))
    

