Python ИЛИ для списка - PullRequest
       49

Python ИЛИ для списка

0 голосов
/ 30 января 2019

В Python вы можете сделать

print (0 or None or False or "" or [] or "hello" or None or "bar")

, который будет печатать

hello

Можете ли вы сделать то же самое со списком?Т.е. есть ли функция Python foo, чтобы следующее также печатало hello?

print (foo([0, None, False, "", [], "hello", None, "bar"]))

Обратите внимание, что bar не печатается.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Вы можете использовать функцию reduce() с оператором or в функции lambda:

from functools import reduce, partial

foo = partial(reduce, lambda x, y: x or y)

print(foo([0, None, False, "", [], "hello", None, "bar"]))
# hello
0 голосов
/ 30 января 2019

Вы можете использовать next(filter(None, ...)) или next(filter(bool, ...)), чтобы найти первое истинное значение из списка:

def foo(l):
    return next(filter(None, l))

Функция filter() принимает и функцию фильтра, иитерируемый и возвращает итератор значений из итерируемого, которые проходят фильтр.

Но когда вы устанавливаете функцию фильтра на None, то это, по сути, то же самое, что и использование bool в качествефункция фильтра, поэтому разрешены только значения, которые равны true .next() функция затем дает вам первое такое значение.

Демо:

>>> def foo(l):
...     return next(filter(None, l))
...
>>> print(foo([0, None, False, "", [], "hello", None, "bar"]))
hello

Вы можете хотите добавить последнее значениев l в качестве значения по умолчанию для вызова next(), если есть только значения Falsey;v1 or v2 or v3 or v4, по крайней мере, выдаст v4, если ни одно из значений не является достоверным, поэтому следующее также делает:

def foo(l):
    return next(filter(None, l), l[-1])

Использование filter(None, ...) на дробь быстрее, чем filter(bool, ...) потому что filter.__next__ реализация тестирует для None перед тестированием для bool;эта разница в скорости очень мала и едва измеряется (в пределах погрешности):

>>> import timeit
>>> import random
>>> t = [random.choice([True, False]) for _ in range(10 ** 6)]
>>> for ff in ('bool', 'None'):
...     count, total = timeit.Timer(f'deque(filter({ff}, t), maxlen=0)', 'from collections import deque; from __main__ import t').autorange()
...     print(f"{ff}: {total / count * 1000:8.4f} ms")
...
bool:  98.9971 ms
None:  95.7907 ms
...