检查给定键是不是已存在于字典中并将其递增

Posted

技术标签:

【中文标题】检查给定键是不是已存在于字典中并将其递增【英文标题】:Check if a given key already exists in a dictionary and increment it检查给定键是否已存在于字典中并将其递增 【发布时间】:2010-10-03 03:40:13 【问题描述】:

给定一个字典,我如何确定该字典中的给定键是否已设置为非无值?

也就是说,我想这样做:

my_dict = 

if (my_dict[key] != None):
  my_dict[key] = 1
else:
  my_dict[key] += 1

也就是说,如果已经有一个值,我想增加该值,否则将其设置为 1。

【问题讨论】:

小代码 nitpick:如果那里已经有东西,则代码将 my_dict[key] 设置为 1,如果没有,则将其递增。我想你想要 ==,而不是 !=。 【参考方案1】:

您正在寻找collections.defaultdict(适用于 Python 2.5+)。这个

from collections import defaultdict

my_dict = defaultdict(int)
my_dict[key] += 1

会做你想做的。

对于普通的 Python dicts,如果给定键没有值,则在访问 dict 时不会得到 None——KeyError 将被引发。所以如果你想使用普通的dict,而不是你的代码,你会使用

if key in my_dict:
    my_dict[key] += 1
else:
    my_dict[key] = 1

【讨论】:

按照他的例子,设置“defaultdict(lambda: 0)”并跳过整个“if”子句应该足够了。 这可行,但会混淆键和值(使其读起来有些奇怪)。 “some_value”应该是“some_key” @nailer:已修复,谢谢。我最初使用了“some_value”,因为这是问题中的变量名,但我同意现在更清楚了。 ...或者对于普通的dicts,您可以使用my_dict[key] = my_dict.get(key, 0) + 1 如何将此扩展到嵌套字典? dict[key1][key2] += 1?【参考方案2】:

我更喜欢在一行代码中做到这一点。

我的字典 = my_dict[some_key] = my_dict.get(some_key, 0) + 1

字典有一个函数,get,它有两个参数——你想要的键和一个默认值(如果它不存在)。我更喜欢这种方法而不是 defaultdict,因为您只想处理这一行代码中不存在密钥的情况,而不是无处不在。

【讨论】:

@AndrewWilkinson 我的错。没有像我应该的那样彻底阅读您的答案。 我更喜欢这个解决方案而不是选择的答案,因为它不需要安装另一个依赖项。 @Erol defaultdict 是 part of the Python standard library。所以不需要安装!【参考方案3】:

我个人喜欢使用setdefault()

my_dict = 

my_dict.setdefault(some_key, 0)
my_dict[some_key] += 1

【讨论】:

setdefault 太棒了。如果已经为some_key 设置了一个值,它不会改变该值。例如d=1:2; d.setdefault(1, 0) 不会干扰d[1] 的值。【参考方案4】:

为此,您需要 key in dict 成语。

if key in my_dict and not (my_dict[key] is None):
  # do something
else:
  # do something else

但是,您可能应该考虑使用defaultdict(按照 dF 的建议)。

【讨论】:

请注意,至少在 2.6 版本中,has_key() 已被弃用,取而代之的是 d 中的 key。我认为在 2.5 中也是如此。 注意可以写my_dict[key] is not None,这样更清楚(至少恕我直言) @brandizzi - 同意,if key in my_dict and my_dict[key]:【参考方案5】:

要回答“如何确定该字典中的给定索引是否已设置为非无值”的问题,我更喜欢这个:

try:
  nonNone = my_dict[key] is not None
except KeyError:
  nonNone = False

这符合已经调用的 EAFP 概念(更容易请求宽恕而不是许可)。它还避免了字典中的重复键查找,就像在 key in my_dict and my_dict[key] is not None 中一样,如果查找成本很高,这很有趣。

对于您提出的实际问题,即增加一个 int 如果它存在,或者将其设置为默认值,我也推荐

my_dict[key] = my_dict.get(key, default) + 1

正如 Andrew Wilkinson 的回答。

如果您在字典中存储可修改的对象,还有第三种解决方案。一个常见的例子是multimap,您可以在其中存储您的键的元素列表。在这种情况下,您可以使用:

my_dict.setdefault(key, []).append(item)

如果字典中不存在 key 的值,setdefault 方法会将其设置为 setdefault 的第二个参数。它的行为就像一个标准的 my_dict[key],返回键的值(可能是新设置的值)。

【讨论】:

看起来确实是 Pythonic(对于像我这样的局外人来说)是任何问题至少有 3 个有效答案:) @davka:嗯,这三个用例几乎相同,但不同:a)找出字典中是否有非None元素b)从字典中检索一个值或使用如果该值不存在,则为默认值 c) 从字典中检索一个值,如果该值尚不存在,则存储一个默认值。 我知道 :) 这不是批评,我只是被这个事实逗乐了 在对@ryeguy 的回答的评论中,Stuart Woodward 建议“语言中异常处理的开销总是比确定该项目是否存在于字典中的哈希表查找大一个数量级”,当您说“它还避免了字典中的重复键查找......如果查找很昂贵” - 有没有人测量异常处理比双键查找更快或更慢的地方? @MichaelFirth 我粗略地搜索了 Python 的异常开销:***.com/questions/2522005/… 它更慢,但不是很多。请记住,抛出异常的高级概念在不同语言中的处理方式非常不同,您无法概括其优缺点。因此,虽然“异常有 10 倍的开销”对于 Java 可能是正确的,但它不适用于 Python(或 Swift 或其他)。【参考方案6】:

同意 cgoldberg。我是怎么做的:

try:
    dict[key] += 1
except KeyError:
    dict[key] = 1

所以要么像上面那样做,要么像其他人建议的那样使用默认字典。不要使用 if 语句。这不是 Pythonic。

【讨论】:

if 语句不是 Pythonic 的? 我认为这是 Python 的 EAFP 不是最佳方式的一种情况。你上面的例子有重复的代码;如果有一天我们想要+=2-=1 怎么办?您必须记住更改两条线。现在看起来可能是一件微不足道的事情,但这些都是愚蠢的小“微不足道”的虫子,它们会回来咬你。 这看起来不错并且工作正常,但我通常避免这样做,因为我认为语言中异常处理的开销总是比确定是否项目在字典中是否存在。【参考方案7】:

正如您从许多答案中看到的那样,有几种解决方案。 LBYL 的一个实例(在你跳跃之前查看)尚未提及,has_key() 方法:

my_dict = 

def add (key):
    if my_dict.has_key(key):
        my_dict[key] += 1
    else:
        my_dict[key] = 1

if __name__ == '__main__':
    add("foo")
    add("bar")
    add("foo")
    print my_dict

【讨论】:

has_key() 比 'in' 运算符慢,可读性差。 ...它已在 Python 2.6 中被弃用并在 Python 3 中被删除。【参考方案8】:

有点晚了,但这应该可以。

my_dict = 
my_dict[key] = my_dict[key] + 1 if key in my_dict else 1

【讨论】:

哇,作为一名 Java 程序员,这是一个看起来很疯狂的结构。它看起来像一个奇序三元运算符?【参考方案9】:

您尝试执行此操作的方式称为 LBYL(在跳跃之前查看),因为您在尝试增加值之前检查条件。

另一种方法称为 EAFP(更容易请求宽恕而不是许可)。在这种情况下,您只需尝试该操作(增加值)。如果失败,您将捕获异常并将值设置为 1。这是一种稍微 Pythonic 的方法 (IMO)。

http://mail.python.org/pipermail/python-list/2003-May/205182.html

【讨论】:

【参考方案10】:

这不是直接回答问题,但在我看来,您可能想要collections.Counter 的功能。

from collections import Counter

to_count = ["foo", "foo", "bar", "baz", "foo", "bar"]

count = Counter(to_count)

print(count)

print("acts just like the desired dictionary:")
print("bar occurs  times".format(count["bar"]))

print("any item that does not occur in the list is set to 0:")
print("dog occurs  times".format(count["dog"]))

print("can iterate over items from most frequent to least:")
for item, times in count.most_common():
    print(" occurs  times".format(item, times))

这会导致输出

Counter('foo': 3, 'bar': 2, 'baz': 1)
acts just like the desired dictionary:
bar occurs 2 times
any item that does not occur in the list is set to 0:
dog occurs 0 times
can iterate over items from most frequent to least:
foo occurs 3 times
bar occurs 2 times
baz occurs 1 times

【讨论】:

Counter 的工作方式与 defaultdict(int) 类似,但具有一些额外的功能,因此在专门处理整数时可以完美运行,但您不会显示任何相关行为。【参考方案11】:

这是我最近想出的用于解决此问题的单行代码。它基于setdefault字典方法:

my_dict = 
my_dict[key] = my_dict.setdefault(key, 0) + 1

【讨论】:

【参考方案12】:

我一直在寻找它,但在网络上没有找到它,然后用 Try/Error 尝试了运气并找到了它

my_dict = 

if my_dict.__contains__(some_key):
  my_dict[some_key] += 1
else:
  my_dict[some_key] = 1

【讨论】:

您不应该在生产代码中使用__contains__。顺便提一句。 __contains__ 与使用 is 相同。 my_dict.__contains__(some_key) 等价于some_key in my_dict,是in 运算符而不是is 的重载

以上是关于检查给定键是不是已存在于字典中并将其递增的主要内容,如果未能解决你的问题,请参考以下文章

MySQL重大Bug!自增主键竟然不是连续递增

SQL - 检查列是不是自动递增

如何获取最后插入的自动递增 id 并将其插入 laravel 中的另一个表中?

Android - 检查元素是不是存在于 WebView 中(在 DOM 中)

检查dict中是不是存在给定项目的列表[重复]

SQL 主键/标识键不是自动递增的