做以下事情的最毕达通的方法是什么:假设我有两本字典A和B。现在,字典的常规python等式将检查每个字典中的值和键是否相同,如果这对字典的每个元素都有效,那么它们是相等的。我想对此进行修改,使之考虑一个字典,如果对于在A中具有相同值的所有键集,则该集合中的每个元素在B中具有相同的值,但不一定与A中的相同。
示例:
A = {'A':1, 'B':4, 'C':1}
B = {'A':9, 'B':2, 'C':9}这里是A == B。从本质上说,这个字典代表了一组集合,我想在它之上实现set相等。
我的尝试
def eq(a,b):
if not a.keys() == b.keys():
return False
for grouping in ({k for k in a.keys() if a[k] == v} for v in a.values()):
if not len(set(b[x] for x in grouping)) == 1:
return False
return True我真的不喜欢这种方法,因为它不会短路,因为必须消耗整个发电机才能将其转换为一组。其思想是将第一个集合划分为组,这样每个组中的每个元素都具有相同的值。然后,我想确保对于每个分组,分组元素的值在另一个集合中是相同的。
编辑很抱歉我不能解释得更清楚,我会给出更多的例子。考虑这个问题的一个更简单的方法是:我可以将任何字典转换成一组集合,如下所示:
A = {'A':3, 'B':3, 'C':3, 'R':4, 'T':4}
A = {{'A', 'B', 'C'}, {'R', 'T'}}
B = {'A':[], 'B':[], 'C':[], 'R':"", 'T':""}
B = {{'A', 'B', 'C'}, {'R', 'T'}}
A == B发布于 2019-06-26 02:51:47
有些变化,我只能做到:
def eq(a,b):
if not a.keys() == b.keys():
return False
for x, y in zip(a.values(), b.values()):
if not sorted([key for key in a.keys() if a[key] == x]) == sorted([key for key in b.keys() if b[key] == y]):
return False
return True但稍微干净一点,就会是:
def eq(a,b):
d1 = {}
d2 = {}
for (x, y), (i, j) in zip(a.items(), b.items()):
d1.setdefault(y, []).append(x)
d2.setdefault(j, []).append(i)
return [sorted(i) for i in d1.values()] == [sorted(i) for i in d2.values()]或更短:
def eq(a,b):
d1 = {y: sorted([i for i in a.keys() if a[i] == y]) for x, y in a.items()}
d2 = {y: sorted([i for i in b.keys() if b[i] == y]) for x, y in b.items()}
return list(d1.values()) == list(d2.values())发布于 2019-06-26 02:52:17
基于@pault建议的一种方法是创建键的值字典,然后查看两个字典的值是否以相同的方式组合在一起。
我还对反向字典的值进行排序,以处理顺序,以及比较它们时的最终值列表。
from collections import defaultdict
def eq(A, B):
rev_A = defaultdict(list)
rev_B = defaultdict(list)
#Create the reverse dictionary
for k, v in A.items():
#If v is a list, convert it to tuple to make a hashable key
if isinstance(v, list):
rev_A[tuple(v)].append(k)
else:
rev_A[v].append(k)
for k, v in B.items():
if isinstance(v, list):
rev_B[tuple(v)].append(k)
else:
rev_B[v].append(k)
#Sort the values of reverse dictionary
for k, v in rev_A.items():
rev_A[k] = sorted(v)
for k, v in rev_B.items():
rev_B[k] = sorted(v)
#See if the values of both dictionaries group in same fashion
return list(sorted(rev_A.values())) == list(sorted(rev_B.values()))
A = {'A':1, 'B':4, 'C':1}
B = {'A':9, 'B':2, 'C':9}
print(eq(A,B))
A = {'A':3, 'B':3, 'C':3, 'R':4, 'T':4}
B = {'C':8, 'R':6, 'T':6, 'A':8, 'B':8}
print(eq(A,B))
A = {'A':3, 'B':3, 'C':3, 'R':4, 'T':4}
B = {'A':[], 'B':[], 'C':[], 'R':"", 'T':""}
print(eq(A,B))输出将是
True
True
True发布于 2019-06-26 02:57:39
编辑:修正了@pault指出的问题。虽然这个特定的输入现在会引发一个错误,因为b 中的值是不可理解的.
因为OP提到他们最初的方法不会短路,所以我会尝试给出一种方法。这种方法确实要求a和b中的值是可选的。
不过,我还没描述过这个。无论如何,这可能取决于输入的性质。具体来说,如果可以散列a或b中的值,但是效率很低,那么这种方法当然会受到影响。
另一个想法是:如果这两个块是相等的(在这个定义下)或接近,那么这个实现需要比较python循环中的所有元素,这可能比其他实现要慢。然而,如果他们可能有很大的不同,允许短路工作,那么这种方法可能会显示出一个优势。
编辑:添加了一个参数encoding来强制散列一些对象。当然,这会产生一些副作用,这取决于所使用的编码,比如[]和()被认为是相等的,而具有不同顺序的等号块被认为是不相等的。
def eq(a, b, encoding = None):
if len(a) != len(b): return False
mapping = {}
value_set = set()
for k, v_a in a.items():
v_b = b.get(k)
if v_b is None: return False
if encoding: v_a, v_b = encoding(v_a), encoding(v_b)
if v_a in mapping:
if mapping[v_a] != v_b: return False
elif v_b in value_set: return False
else:
mapping[v_a] = v_b
value_set.add(v_b)
return True用法:
import json
A = {'A':3, 'B':3, 'C':3, 'R':4, 'T':4}
B = {'A':[], 'B':[], 'C':[], 'R':"", 'T':""}
print(eq(A, B, encoding = json.dumps))https://stackoverflow.com/questions/56764377
复制相似问题