Когда следует использовать list.count(0) и как мне сбрасывать товар "False"?
a.count(0)
всегда возвращает 11, поэтому что мне делать, чтобы скинуть False
и вернуть 10?
a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
Ответы
Ответ 1
Python 2.x интерпретирует False
как 0
и наоборот. AFAIK даже None
и ""
можно считать False
в условиях.
Переопределить счет следующим образом:
sum(1 for item in a if item == 0 and type(item) == int)
или (спасибо Кевин и Bakuriu за свои комментарии):
sum(1 for item in a if item == 0 and type(item) is type(0))
или как предложено ozgur в комментариях (, который не рекомендуется и считается неправильным, см. this), просто:
sum(1 for item in a if item is 0)
он может ( "является" оператор ведет себя неожиданно с целыми числами) работает для небольших первичных типов, но если ваш список содержит объекты, пожалуйста, рассмотрим, что делает оператор is
:
Из документации для оператора is
:
Операторы is
и is not
проверяют идентичность объекта: x is y
истинно тогда и только тогда, когда x и y являются одним и тем же объектом.
Дополнительная информация о операторе is
: Понимание Python "is" operator
Ответ 2
Это можно сделать с помощью sum
и выражения-генератора, которое сравнивает каждый элемент с False
:
>>> a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> sum((x == 0 and x is not False) for x in a)
10
Это работает, потому что bool
является подклассом int
- False
равно 0 и True
равно 1.
Ответ 3
Вам нужно отфильтровать Falses самостоятельно.
>>> a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> len([x for x in a if x == 0 and x is not False])
10
Старый ответ специфичен для CPython, и лучше использовать решения, которые работают на всех реализациях Python.
Так как CPython хранит пул небольших целых объектов, нуль включен, вы можете отфильтровать список с помощью оператора is
.
Это, конечно, не следует использовать для сравнения значений, но в этом случае оно работает, так как нули - это то, что мы хотим найти.
>>> a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> [x for x in a if x is 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> len(_)
10
Ответ 4
Как об этом решении функционального стиля:
print zip(a, map(type, a)).count((0, int))
>>> 10
Считая это против некоторых других ответов здесь, это также кажется одним из самых быстрых:
t0 = time.time()
for i in range(100000):
zip(a, map(type, a)).count((0, int))
print time.time() - t0
>>> 0.275855064392
t0 = time.time()
for i in range(100000):
sum(1 for item in a if item == 0 and type(item) == int)
print time.time() - t0
>>> 0.478030204773
t0 = time.time()
for i in range(100000):
sum(1 for item in a if item == 0 and type(item) is type(0))
print time.time() - t0
>>> 0.52236700058
t0 = time.time()
for i in range(100000):
sum((x==0 and x is not False) for x in a)
print time.time() - t0
>>> 0.450266122818
Ответ 5
Решая эту проблему в более общем плане, вы можете создать свой собственный подкласс списка:
class key_equality_list(list):
def __init__(self, key, items):
super(key_equality_list, self).__init__(items)
self._f = key
def __contains__(self, x):
return any(self._f(x) == self._f(item) for item in self)
def count(self, x):
return sum(self._f(x) == self._f(item) for item in self)
И затем определите ключевую функцию, которая проверяет типы:
type_and_val = lambda x: (x, type(x))
Итак, ваше использование будет:
>>> a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> a = key_equality_list(type_and_val, a)
>>> a.count(0)
10
>>> a.count(False)
1
Ответ 6
Другой вариант - сначала "украсить" список, добавив типы и счетчик:
decorated_seq = list(map(lambda x: (x, type(x)), sequence))
decorated_seq.count((0, type(0)))
Если вы хотите иметь 0 == 0.0
, вы можете сделать:
decorated_seq = list(map(lambda x: (x, isinstance(x, bool)), sequence))
decorated_seq.count((0, False))
Что подсчитывает все 0
, которые не относятся к типу bool
(т.е. False
s).
Таким образом, вы можете определить, что count
должно делать так, как вам угодно, за счет создания временного списка.
Ответ 7
Так как count
возвращает количество элементов, равное его вводу, а так как 0
равно False
в Python, один из способов приблизиться к этому - передать что-то, равное 0
, но не равным False
.
Сам Python не предоставляет такого объекта, но мы можем написать его:
class Zero:
def __eq__(self, other):
return other == 0 and other is not False
print([1, 2, 0, False].count(Zero()))
Помните, что в Python есть другие вещи, которые, как и False
, равны 0
. Я могу думать о 0.0
, decimal.Decimal(0)
и fractions.Fraction(0,1)
. Кроме того, любой может подклассифицировать int
для создания других "поддельных значений 0", как и False
. В приведенном выше коде учитывается все из них, рассматривая False
как единственный частный случай, но вы можете сделать что-то другое в своем __eq__
.
Конечно, "под обложками" это очень похоже на простое выполнение sum(other == 0 and other is not False for other in a)
. Но, учитывая, как count()
определен, неудивительно, что a.count(x)
похож на sum(x == y for y in a)
.
Вы сделали бы это только в редком случае, когда по какой-то причине вы решили использовать count
(возможно, потому, что вы используете какой-то сторонний код, который будет его называть), и вам нужно придумать подходящий объект для его прохождения. В основном, он рассматривает count
как функцию, которая вызывает произвольную функцию, которую мы пишем (требуя только, чтобы эта функция была функцией __eq__
аргумента) и подсчитывала количество истинных возвращаемых значений. Это точное описание того, что делает count
, но не действительно точка count
, поскольку sum
является более явным.
Ответ 8
Многие соответствующие ответы уже даны. Конечно, альтернативой является фильтрация списка по типу элемента, который вы запрашиваете для первого.
>>> a = ["a",0,0,"b",None,"c","d",0,1,False,0,1,0,3,[],0,1,9,0,0,{},0,0,9]
>>> def count(li, item):
... return list(filter(lambda x: type(x) == type(item), li)).count(item)
...
>>>
>>> count(a, 0)
10
>>> count(a, False)
1
>>> count(a, "a")
1
>>> class my_own_int(int): pass
...
>>> a.append(my_own_int(5))
>>> a.count(5)
1
>>> count(a, 5)
0
Если вас беспокоит копия, вы можете использовать sum
и злоупотреблять тем, что мы пытаемся обойти выше (это True == 1
).
def count(li, item):
return sum(map(lambda x: x == item, filter(lambda x: type(x) == type(item), li)))
Ответ 9
Если вы часто сталкиваетесь с такими проблемами, вы можете ввести следующий класс *
class Exactly:
def __init__(self, something):
self.value = something
def __eq__(self, other):
return type(self.value) == type(other) and self.value == other
и используйте его следующим образом:
a.count(Exactly(0))
* Конечно, вам может потребоваться усилить его и для других операций.