我正在寻找一种通过寻址与给定键不匹配的所有键来更新/访问Python字典的方法。
也就是说,我想做dict[key]
之类的事情,而不是通常的dict[!key]
。我发现了一种解决方法,但我认为必须有一种更好的方法,我现在无法弄清楚。
# I have a dictionary of counts
dicti = {"male": 1, "female": 200, "other": 0}
# Problem: I encounter a record (cannot reproduce here) that
# requires me to add 1 to every key in dicti that is NOT "male",
# i.e. dicti["female"], and dicti["other"],
# and other keys I might add later
# Here is what I am doing and I don't like it
dicti.update({k: v + 1 for k,v in dicti.items() if k != "male"})
答案 0 :(得分:5)
dicti.update({k: v + 1 for k,v in dicti.items() if k != "male"})
创建子字典(散列,内存开销)然后将其传递给旧字典:更多散列/引用副本。
为什么键上没有好的循环(因为值不可变):
for k in dicti:
if k != "male":
dicti[k] += 1
如果有很多键并且只有一个键可以避免,可能会更快:添加到所有键,并取消对要避免的一个键的操作(节省大量的字符串比较):
for k in dicti:
dicti[k] += 1
dicti["male"] -= 1
如果值是可变的(例如:列表),我们将避免一次散列并改变该值:
for k,v in dicti.items():
if k != "male":
v.append("something")
单行很酷,但有时避免使用它们(在这种情况下的性能和可读性)
答案 1 :(得分:3)
如果您必须更频繁地执行此“添加到其他人”操作,并且如果所有值都是数字,您还可以从给定键中减去并将相同的值添加到某个全局变量计算所有值(包括相同的键)。例如,作为包装类:
import collections
class Wrapper:
def __init__(self, **values):
self.d = collections.Counter(values)
self.n = 0
def add(self, key, value):
self.d[key] += value
def add_others(self, key, value):
self.d[key] -= value
self.n += value
def get(self, key):
return self.d[key] + self.n
def to_dict(self):
if self.n != 0: # recompute dict and reset global offset
self.d = {k: v + self.n for k, v in self.d.items()}
self.n = 0
return self.d
示例:
>>> dicti = Wrapper(**{"male": 1, "female": 200, "other": 0})
>>> dicti.add("male", 2)
>>> dicti.add_others("male", 5)
>>> dicti.get("male")
3
>>> dicti.to_dict()
{'other': 5, 'female': 205, 'male': 3}
优点是add
和add_others
操作都是O(1),只有当您真正需要它们时,才能使用全局偏移更新值。当然,to_dict
操作仍然是O(n),但更新后的dict可以保存,只有在中间再次调用add_other
时才重新计算。