开发者

Concise way to call ifilter with multiple predicates in python

I'm streaming a very large collection through a script and am currently using ifilter in a simple call to reject certain values, i.e.:

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

That's one predicate, but now it's occurred to me I should add another, and I might want to add others in the future. The straightforward way would've been nesting an ifilter call:

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

I am thinking of simply putting the predicates as unbound functions in a list and using them for this. These repeated ifilter calls seem hard to attain there though (and might not be the best option). Perhaps I can construct a single function that calls all the predicates but how开发者_运维问答 do I write this as concisely (while still readable) as possible?


You could write the following function:

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

You would then call it like so:

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

And you could implement a similar disjoin function for or-ing functions together:

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

There may be a nicer way to implement them, but one has to be careful. One might try applying every function to x and using all or any, but this is undesirable, since using them will require evaluating every predicate on the argument. The solution presented here is satisfactorily short-circuiting.

Also, just for fun, let's implement an invert function

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

Now, we have a functionally complete set of function-manipulating functions, and can construct any logical operation out of these :)


I would stick with the following solution:

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

or

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

and then

ifilter(complex_predicate, read_records(filename))

or the same with complex_predicate2.

But, I think it is a matter of taste, though.


If there are only two predicates, I would come up with the following:

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

Also, as it was mentioned above, if there are more than two predicates, it's better to put all the predicates in the specific function. Using all makes the condition block much less messy (because all predicates get separated by comma in this case).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜