我有一个元组字典,例如:
my_dict = {('A','B'): 3, ('A','C'): 4, ('B','A'): 5}
目标是组合键(无论顺序如何)并添加它们各自的值,这样结果看起来像
my_dict = {('A','B'): 8, ('A','C'): 4}
我很确定我可以通过以下方式做到这一点:
new_dict = {}
items = my_dict.copy().items()
for k, _ in items:
to_add = my_dict.pop(k)
for key, val in my_dict.items():
if set(k) == set(key):
new_dict[key] = val + to_add
if (k not in new_dict) and ((k[1],k[0]) not in new_dict):
new_dict[k] = to_add
但是,我对这个解决方案不是很满意。我创建了另一个字典而不是维护原始字典,我有嵌套循环(虽然我不认为它是 O(N**2) 因为第二个循环的长度总是在减少),我觉得有更多优雅的解决方案。
是否有更 pythonic 或通常更优雅的方法来完成此任务?
编辑:
为了清楚起见,这里有一些成立的条件——所有元组都恰好有 2 个元素,但不能保证这些元素是可比较的,因为我们可能有 ('A', None)。不存在任何重复的元组,例如 ('A', 'A'),并且元组的最终顺序并不重要。这意味着结果
my_dict = {('A','B'): 8, ('A','C'): 4}
不比
更好或更差my_dict = {('B','A'): 8, ('A','C'): 4}
请您参考如下方法:
如果您既不关心元组中的顺序也不关心元组中的重复项(也就是说,如果您的代码将 ('A', 'B') 转换为 ('B', 'A' ),并将 ('A', 'A') 转换为 ('A',),这很好),您可以使用 frozensets 而不是元组。
如果您关心重复而不关心顺序,排序的元组将起作用。 (虽然如果你的元组元素不可比较,你需要想出一个比较键——也许只是 lambda x: type(x).__name__, x la Python 2,但也许更复杂的东西。)
无论哪种方式,与其构建一个 dict,然后构建另一个对重复项求和的 dict,不如首先构建一个 Counter:
import collections
c = collections.Counter()
for key, value in <wherever they come from>:
c[frozenset(key)] += value
import collections
c = collections.Counter()
for key, value in <wherever they come from>:
c[tuple(sorted(key))] += value
如果你需要保留但忽略顺序(同样的方式,例如,一些文件系统保留但忽略大小写),你需要做更多的工作。 (您还需要决定是否要保留一组匹配的键中的第一个或最后一个。)一个选择是使用包装字典的“键转换字典”,使用转换后的键作为基础键和原始键作为值中的额外值。没有包装器,它看起来像这样:
c = {}
for key, value in <wherever they come from>:
skey = frozenset(key)
if skey not in c:
c[skey] = [key, 0]
c[skey][1] += value
