我有一个元组字典,例如:
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}
答案 0 :(得分:3)
如果您不关心元组中的顺序或重复(即,如果您的代码将('B', 'A')
转换为('A', 'A')
,将('A',)
转换为lambda x: type(x).__name__, x
,那么&#39 ;很好),你可以使用frozensets而不是元组。
如果您关心重复但不关心顺序,排序的元组将起作用。 (虽然如果你的元组元素不具有可比性,你需要提出一个比较键 - 可能只是Counter
一个Python 2,但可能更复杂。)
无论哪种方式,而不是建立一个字典,然后建立另一个总结重复的字典,只需在第一时间建立一个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
如果你需要保留但忽略顺序(同样的方式,例如,某些文件系统保留但忽略了大小写),你需要做更多的工作。 (您还需要决定是否要保留匹配的一组键中的第一个或最后一个。)一个选项是使用&#34;键转换字典&#34;包装dict,使用转换后的键作为底层键,将原始键作为值中的额外值。没有包装器,它看起来像这样:
redux-thunk
答案 1 :(得分:2)
要获得更加pythonic的解决方案,请使用collections.defaultdict
或collections.Counter
:
import collections
new_dict = collections.defaultdict(int)
# alternatively: new_dict = collections.Counter()
for key, value in my_dict.items():
# converting the tuples to frozensets removes the order and makes
# them hashable
key = frozenset(key)
new_dict[key] += value
# turn the defaultdict with frozensets back into a normal dict with tuples
new_dict = {tuple(key): value for key, value in new_dict.items()}
结果:
{('A', 'B'): 8, ('A', 'C'): 4}
请记住,只有在元组中的值是唯一的时,这才有效。如果dict中有('A', 'A')
这样的元组,则在其上调用frozenset
会将其折叠为{'A'}
并产生错误的输出。如果这是一个问题,您可以替换
key = frozenset(key)
带
key = tuple(sorted(key))
使其正常工作。