Краткий способ вызова ifilter с несколькими предикатами в python - PullRequest
3 голосов
/ 29 июня 2010

Я транслирую очень большую коллекцию через скрипт и в настоящее время использую ifilter в простом вызове, чтобы отклонить определенные значения, т.е.

ifilter(lambda x: x in accept_list, read_records(filename))

Это один предикат, но теперь мне пришло в голову, что я должен добавить другой, и я мог бы захотеть добавить другие в будущем. Простым способом было бы вложить ifilter вызов:

ifilter(lambda x : x not in block_list,
    ifilter(lambda x: x in accept_list, read_records(filename)))

Я думаю просто поместить предикаты как несвязанные функции в список и использовать их для этого. Эти повторные вызовы ifilter кажутся труднодостижимыми (и, возможно, не лучшим вариантом). Возможно, я смогу создать одну функцию, которая будет вызывать все предикаты, но как мне написать это как можно более кратко (пока еще читабельно)?

Ответы [ 3 ]

5 голосов
/ 30 июня 2010

Вы могли бы написать следующую функцию:

def conjoin(*fns):
    def conjoined(x):
        for fn in fns:
            if not fn(x): return False
        return True
    return conjoined

Затем вы бы назвали ее так:

ifilter(conjoined(lambda x: x not in block_list, lambda x: x in accept_list),
        read_records(filename))

И вы могли бы реализовать аналогичную функцию disjoin для или -ing-функции вместе:

def disjoin(*fns):
    def disjoined(x):
        for fn in fns:
            if fn(x): return True
        return False
    return disjoined

Возможно, есть более хороший способ их реализации, но нужно быть осторожным.Можно попробовать применить каждую функцию к x и использовать all или any, но это нежелательно, поскольку для их использования потребуется оценка каждого предиката в аргументе.Представленное здесь решение удовлетворительно короткое замыкание.

Также, просто для удовольствия, давайте реализуем функцию invert

def invert(fn):
    return lambda x: not fn(x)

Теперь у нас есть функционально завершенных набор функций, управляющих функциями, и может создавать любые логические операции из них:)

1 голос
/ 29 июня 2010

Я бы придерживался следующего решения:

def complex_predicate(x):
    return x not in block_list and x in accept_list and is_good(x)

или

def complex_predicate2(x):
    return all([x not in block_list, x in accept_list, is_good(x)])

и затем

ifilter(complex_predicate, read_records(filename))

или то же самое с complex_predicate2.

Но я думаю, что это вопрос вкуса.

0 голосов
/ 17 августа 2011

Если есть только два предиката, я бы придумал следующее:

ifilter(lambda x: x in accept_list and x not in block_list, read_records(filename))

Также, как уже упоминалось выше, если существует более двух предикатов, лучше поместить все предикатыв конкретной функции.Использование all делает блок условий намного менее запутанным (потому что в этом случае все предикаты разделяются запятой).

...