Python filter / max combo - проверка пустого итератора
(Использование Python 3.1)
Я знаю, что этот вопрос задавался много раз для общего вопроса тестирования, если итератор пуст; очевидно, нет четкого решения этой проблемы (я думаю, по какой-то причине - итератор на самом деле не знает, пуст ли он, пока его не попросят вернуть его следующее значение).
Однако у меня есть конкретный пример, и я надеялся, что смогу сделать из него чистый и Pythonic-код:
#lst is an arbitrary iterable
#f must return the smallest non-zero element, or return None if empty
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
if # somehow check that flt is empty
return None
return min(flt)
Есть ли лучший способ сделать это?
РЕДАКТИРОВАТЬ: извините за глупые обозначения. Параметр функции действительно произвольный итеративный, а не список.
5 ответов
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
try:
return min(flt)
except ValueError:
return None
min
бросает ValueError
когда последовательность пуста. Это следует общепринятой парадигме "Проще просить прощения".
РЕДАКТИРОВАТЬ: решение на основе сокращения без исключений
from functools import reduce
def f(lst):
flt = filter(lambda x : x is not None and x != 0, lst)
m = next(flt, None)
if m is None:
return None
return reduce(min, flt, m)
t = [1,2,3]
if any(filter(lambda x: x == 10, t)):
print("found 10")
def f(lst):
# if you want the exact same filtering as the original, you could use
# lst = [item for item in lst if (item is not None and item != 0)]
lst = [item for item in lst if item]
if lst: return min(lst)
else: return None
понимание списка допускает только те элементы, которые не оцениваются как логическое false (что отфильтровывает 0 и None)
пустой список, т. е. [] будет иметь значение False, поэтому "if lst:" сработает только в том случае, если в списке есть элементы
Если вы просто хотите проверить, пуст ли возвращаемый фильтр, вы можете сделать (Python3)
len(list(filter(lambda e : e == 2, [1,2,3])))
Но обратите внимание, следовательно, фильтр является генератором, если вы выполните этот тест дважды, второй раз вы получите другой результат:
len(list(filter(lambda e : e == 2, [1,2,3])))
len(list(filter(lambda e : e == 2, [1,2,3])))
>>> 1
>>> 1
Но:
f = filter(lambda e : e == 2, [1,2,3])
len(list(f))
len(list(f))
>>> 1
>>> 0
Вы можете пойти на уменьшение выражения тоже return reduce(lambda a,b: a<b and a or b,x) or None