【问题标题】:Distinguish 0 from False when counting elements of a list计算列表元素时区分 0 和 False
【发布时间】:2017-06-18 07:35:02
【问题描述】:

假设我有一个值列表,其中包含一些 0s 和一些 Falses。 类似的东西

arr = [0, False, False, 0, False]

如何在 Python 中计算它们中的每一个?

list.count 在这里不起作用:

>>> arr.count(0)
5
>>> arr.count(False)
5

【问题讨论】:

  • 您要解决的实际问题是什么?我怀疑首先可能有更好的方法。例如,如果要在列表中使用占位符元素,最好使用None 而不是False
  • 没有特别的问题。这就是我想弄清楚的。

标签: python list count zero


【解决方案1】:

区分的唯一方法是通过它们的类型:

>>> type(False)
bool
>>> type(0)
int

但是isinstance 不能用于0,因为boolint 的子类

>>> isinstance(0, bool)
False
>>> isinstance(False, int)
True

而且值是相等的(这就是为什么count 不能“正确”为您工作):

>>> 0 == False
True

您可以使用 0 是 CPython(可能还有其他 Python 实现)中的内部(单例)整数和 False 也是单例的事实:

>>> 0 is 0
True
>>> False is False
True
>>> 0 is False
False

至于解决方案:使用不等于的东西,例如None

arr = [0, None, None, 0, None]

arr.count(0)     # 2
arr.count(None)  # 3

如果你真的需要使用0False,你可以使用sum(就像其他人展示的那样):

sum(x is False for x in arr)  # for count(False)
sum(x is 0 for x in arr)      # for count(0)

或独立于 Python 实现:type 和值作为标识符和 collections.Counter

>>> arr = [0, False, False, 0, False]

>>> from collections import Counter

>>> Counter((type(x), x) for x in arr)
Counter({(bool, False): 3, (int, 0): 2})

【讨论】:

  • 在这里使用isinstance到底有什么问题?您可以轻松检查它是否不是布尔值?
  • 没问题,但逻辑不同:if isinstance(x, bool)(算False)和if **not** isinstance(x, bool)(算0)。这并不能概括“好”。
  • not isinstance(x, bool) and x == 0?
  • @poke 我的意思是not 在两种方法之间有所不同,这使得它不对称。我想展示在实例相等但它们的类不同时有效的通用方法。 sum(x is 0 for x in arr)sum(x is False for x in arr) 不是通用的,但至少是对称的。例如,当它包含浮点数0.0、整数0 和布尔值False 时,它会变得非常复杂。 :D
【解决方案2】:

一种选择是使用isFalse 进行比较:

print(sum(1 for x in arr if x is False))

结果:3

(也适用于is 0 BTW)

编辑:我们也可以依赖 True==1 毕竟:sum(x is False for x in arr) 更简单。

【讨论】:

  • 我认为不能保证有一个 0 对象 - 这可能会工作,但不能保证。
  • 这肯定是最好的方法,因为0False 是单例,对吧?
  • 好吧,也不能保证False 是一个单例 :-) 在 CPython 中恰好是这种情况(可能所有其他 python 实现都是这样,因为它“有意义”)。
  • 虽然这会比list.count 慢很多,如果有一个list.count 等效于身份(而不是相等)会很好吗?
  • @MSeifert Guido says they are singletons。这与您可能得到的“按规格”一样接近:P
【解决方案3】:

这是一种使用defaultdict 来同时查找 0 和 False 的计数的方法:

In [73]: from collections import defaultdict

In [74]: d = defaultdict(int)

In [75]: for i in arr:
   ....:     d[str(i)] += i is False or 1 # if I is not False is 0
   ....:     

In [76]: d
Out[76]: defaultdict(<class 'int'>, {'0': 2, 'False': 3})

【讨论】:

    【解决方案4】:

    这是一种罕见的情况,只使用类型检查似乎是明智的。

    sum(1 for item in arr if item == 0 and type(item) is type(0))
    

    正如 Jean-François 所提到的,如果您保证只有 0 和 False,则类型检查本身就足够了。

    【讨论】:

    • 如果只有0和False这两个值,类型检查就足够了。
    • 你在这里和支持者说话,所以我不知道 :)
    • @Jean-FrançoisFabre 哦,伙计,那是给你打电话的吗?如果是这样,我很抱歉大声笑:P
    • 完全没问题!由于 downvoter 不是用户(可能是:))最后一个评论者被 ping 通。我想知道你为什么也投了反对票……
    猜你喜欢
    • 1970-01-01
    • 2013-12-02
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 2020-10-24
    • 2019-01-21
    相关资源
    最近更新 更多