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

Другие вопросы по тегам