比较两个不同的 python 计数器对象

Comparing two different python counter objects

我正在 Python 中研究一种算法,该算法会接受用户输入并告诉他们需要添加哪些新字母到字符串中以使其成为不同的字符串,我一直经常使用 Counter 方法创建的字典。

我想比较两个不同的字典,它们计算字符串中的字母(比如使用集合模块中的计数器工具返回的对象)。我们可以称这些字典为 D1 和 D2。我希望有两个结果字典(R1 和 R2),第一个是两者之间的共享字母,第二个是将 R1 变成 R2 所需的字母(D2 中但不在 D1 中的字母)。

例如:

# assuming they’ve been converted from counter objects into regular 
dictionaries #

D1 = {‘A’: 2, ‘B’: 1, ‘C’: 4, ‘D’: 5}
D2 = {‘A’: 3, ‘B’: 4, ‘C’ : 4, ‘D’: 7}

# Some sort of comparison function executed here #

结果:

R1={‘A’: 2, ‘B’: 3, ‘C’: 4, ‘D’: 5} 
R2 = {‘A’: 1, ‘B’: 1, ‘C’: 0 , ‘D’: 2} 

我无法理解问题,但据我了解:

R1 = {k: min(v, D2[k]) for k, v in D1.items()}
R2 = {k: abs(v - D2[k]) for k, v in D1.items()}

结果

>>> {k: min(v, D2[k]) for k, v in D1.items()}
{'A': 2, 'B': 1, 'C': 4, 'D': 5}
>>> {k: abs(v - D2[k]) for k, v in D1.items()}
{'A': 1, 'B': 3, 'C': 0, 'D': 2}

这些操作已经内置到 Counter 类型中:

Several mathematical operations are provided for combining Counter objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and maximum of corresponding counts.

(引自Python collections.Counter docs。)

所以假设 D1D2 是计数器,尝试

R1 = D1 & D2
R2 = D2 - R1

如果共享字母是指计数器交集,则可以使用 & 运算符,将 R1 转换为 R2 所需的字母数量可以看作是差异:

from collections import Counter

D1 = Counter({'A': 2, 'B': 1, 'C': 4, 'D': 5})
D2 = Counter({'A': 3, 'B': 4, 'C': 4, 'D': 7})

R1 = D1 & D2

print(R1)  # intersection:  min(c[x], d[x])
print(D2 - D1)  # subtract (keeping only positive counts)

输出

Counter({'D': 5, 'C': 4, 'A': 2, 'B': 1})
Counter({'B': 3, 'D': 2, 'A': 1})

如果你想保留负数,你可以这样做:

from collections import Counter

D1 = Counter({'A': 2, 'B': 1, 'C': 4, 'D': 5, 'E': 5})
D2 = Counter({'A': 3, 'B': 4, 'C': 4, 'D': 7, 'E': 3})

R2 = Counter({key: D2.get(key, 0) - value for key, value in D1.items()})
print(R2)

输出

Counter({'B': 3, 'D': 2, 'A': 1, 'C': 0, 'E': -2})

在上面的例子中'E' : -2因为E的计数在D1中是5,在D2中是3注意:所有例子都在Python3.5.

IntersectCounter=[]
for each in D1:
        if D1[each]==D2[each]:
              IntersectCounter.append(each)

这给出了计数器 D1 和 D2 的共同内容

自 Dani Mesejo 的回答以来,添加了 subtract 方法 (docs) 以在 Counter 对象中保留负计数(但是仅就地),即以下是更简洁的解决方案:

from collections import Counter

D1 = Counter({'A': 2, 'B': 1, 'C': 4, 'D': 5, 'E': 5})
D2 = Counter({'A': 3, 'B': 4, 'C': 4, 'D': 7, 'E': 3})

R1 = D1 & D2
print(R1)  

D2.subtract(D1)
print(D2)

输出:

Counter({'D': 5, 'C': 4, 'E': 3, 'A': 2, 'B': 1})
Counter({'B': 3, 'D': 2, 'A': 1, 'C': 0, 'E': -2})