如何比较Python中的两个字典列表?
如何比较dict
的两个列表?结果应该是奇数的了,从字典B.名单如何比较Python中的两个字典列表?
例子:
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}]
在这里,我想和1dB的比较LDA。它应该打印下面的输出。
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}
我已经通过了下面的链接,但它只返回名称,但我想要名称和值如上。
List of Dicts comparision to match between lists and detect value changes in Python
对于一般的解决方案,请考虑以下内容。即使用户在列表中出现故障,它也会适当地进行区分。
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()]
然后,您可以检查的解决方案:
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'))
正如Karl在他的回答中指出的那样,您需要在自定义比较运算符中替换'dict_diff'函数中的'!='比较,因为您正在比较浮点值。或者,在这种情况下,您可以用'min'或'max'(或任何适合您的需要)替换'lambda l,r:r'。 – 2011-06-13 17:39:01
现在,这是工业实力!我认为'dict_diff'中的'merge'的调用应该是'user_diff'。 – 2011-06-13 17:49:57
@Karl:它像广告中那样工作,我实际上测试了它。合并函数是'user_diff',就像在'special_diff'中传递给'dict_diff'一样。这种间接方式允许使用相同的算法来区分列表并区分各个用户。 – 2011-06-13 17:51:55
我会假设相应dict
s为在这两个列表的顺序相同。
根据这一假设,您可以使用下面的代码:
def diffs(L1, L2):
answer = []
for i, d1 in enumerate(L1):
d = {}
d2 = L2[i]
for key in d1:
if key not in d1:
print key, "is in d1 but not in d2"
elif d1[key] != d2[key]:
d[key] = d2[key]
answer.append(d)
return answer
未经检验。请评论是否有错误,我会修复它们
首先,我想感谢您的回复,这里只返回不同的值,但我需要从用户特定的不同值ldB – newbe 2011-06-13 17:10:05
你是什么意思“用户特定”?你的意思是你想比较字典中“User”的值是否相同,或者你的意思是你想只比较将作为输入提供给函数的某些键吗? – inspectorG4dget 2011-06-13 18:28:29
我的方法:根据要排除的值的ldA构建查找,然后确定从ldB中排除每个列表中适当值的结果。
lookup = dict((x['user'], dict(x)) for x in ldA)
# 'dict(x)' is used here to make a copy
for v in lookup.values(): del v['user']
result = [
dict(
(k, v)
for (k, v) in item.items()
if item['user'] not in lookup or lookup[item['user']].get(k, v) == v
)
for item in ldB
]
You should, however, be aware that comparing floating-point values like that can't be relied upon。
感谢您的回复+1 – newbe 2011-06-14 01:37:23
这绝对需要从您的示例数据中进行一些假设,主要是ldA
中不会有用户不在ldB
中,如果这是一个无效假设,请告诉我。你可以称之为dict_diff(ldA, ldB, user)
。
def dict_diff(ldA, ldB, key):
for i, dA in enumerate(ldA):
d = {key: dA[key]}
d.update(dict((k, v) for k, v in ldB[i].items() if v != dA[k]))
print "ldB -> " + str(d)
for dB in ldB[i+1:]:
print "ldB -> " + str(dB)
+1,非常感谢您的回复 – newbe 2011-06-14 01:35:08
还有一个解决方案有点怪异(对不起,如果我错过的东西),但它也可以让你配置自己的平等检查(你只需要修改拉姆达的isEqual此),以及给你如何处理的情况下,两种不同的选择时,按键的不同:
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}]
ldA.extend((ldB.pop() for i in xrange(len(ldB)))) # get the only one list here
output = []
isEqual = lambda x,y: x != y # add your custom equality check here, for example rounding values before comparison and so on
while len(ldA) > 0: # iterate through list
row = ldA.pop(0) # get the first element in list and remove it from list
for i, srow in enumerate(ldA):
if row['user'] != srow['user']:
continue
res = {'user': srow['user']} #
# next line will ignore all keys of srow which are not in row
res.update(dict((key,val) for key,val in ldA.pop(i).iteritems() if key in row and isEqual(val, row[key])))
# next line will include the srow.key and srow.value into the results even in a case when there is no such pair in a row
#res.update(dict(filter(lambda d: isEqual(d[1], row[d[0]]) if d[0] in row else True ,ldA.pop(i).items())))
output.append(res)
break
else:
output.append(row)
print output
@andrew +1,非常感谢回复 – newbe 2011-06-14 01:35:51
我写this tool而回,它目前可以合作pe嵌套列表,字典和集合。为您提供了一个更简洁的输出(在. > i:1 > 'c'
的.
指顶层和i:1
指列表索引1进行比较):
compare(ldA, ldB)
. > i:0 > 'b' dict value is different:
100.0
99.9
. > i:0 > 'd' dict value is different:
48.9
43.7
. > i:1 > 'a' dict value is different:
46.7
67.7
. > i:1 > 'c' dict value is different:
0.0
1.1
. lists differed at positions: 2
['<not present>']
[{'c': 2.2, 'd': 6.5, 'a': 89.9, 'user': 'nameC', 'b': 77.3}]
这里没有任意结构的层次差异,所以你需要写基于你对数据的了解,一个更为复杂的算法。 '用户'是一个特殊的密钥?是否用于在列表中的项目之间建立对应关系(假设'ldB'出现故障,结果应该如何)? – 2011-06-13 16:56:23
是的,这里用户特殊键 – newbe 2011-06-13 16:59:27
对于程序的其余部分以及这里,可能更有意义的是让结构更像'ldA = {'userA':{'a':1,'b': 2,...},...}'。 – 2011-06-13 17:27:32