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]
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]
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
Это можно сделать с помощью 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.
Вам нужно отфильтровать 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
Как об этом решении функционального стиля:
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
Решая эту проблему в более общем плане, вы можете создать свой собственный подкласс списка:
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
Другой вариант - сначала "украсить" список, добавив типы и счетчик:
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
должно делать так, как вам угодно, за счет создания временного списка.
Так как 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
является более явным.
Многие соответствующие ответы уже даны. Конечно, альтернативой является фильтрация списка по типу элемента, который вы запрашиваете для первого.
>>> 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)))
Если вы часто сталкиваетесь с такими проблемами, вы можете ввести следующий класс *
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))
* Конечно, вам может потребоваться усилить его и для других операций.