Alexander
Alexander

Reputation: 1388

Filtering with a only one conditional

I'm trying to write a code that uses only lambdas, filter, map and reduce (its a riddle) that accepts a tuple of integers and a tuple of functions, and returns a new tuple of integers who only return one true from the list of functions:

As an example, if the tuple is (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) and the tuple of functions is (lambda x: x > 3, lambda x: x % 2 == 0) I should get a new tuple that looks like [2, 5, 7, 9] because they make only one of the two rules to return True. this is my code so far and I have no idea how to do that...

func = (lambda x: x > 3, lambda x: x % 2 == 0)
data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

a = lambda func, data: tuple(filter(lambda x: tuple(filter(None, map(lambda f: f(x), func))), data))
print(a(func, data))

This code returns only the integers that apply to both of the terms, but I need to make it to just one.

Upvotes: 0

Views: 97

Answers (2)

Julien
Julien

Reputation: 15249

Here it is:

a = lambda func, data: tuple(filter(lambda d: (sum(map(lambda f: f(d), func)) == 1), data))

Since this really is just a contrived exercise for the sake of it I won't endeavor explaining this horrible expression. But the way to get to it is to first write the code in a clear way with for loops, if blocks etc..., and then one step at a time replace each component with the appropriate map, filter etc...

The one trick I use here is automatic boolean conversion to int: sum(sequence_of_bool) == 1 means exactly one bool is True.

My full test code:

func = (lambda x: x > 3, lambda x: x % 2 == 0)
data = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
a = lambda func, data: tuple(filter(lambda d: (sum(map(lambda f: f(d), func)) == 1), data))
print(a(func, data))

(2, 5, 7, 9)

Upvotes: 1

blhsing
blhsing

Reputation: 107134

You can use bool.__xor__ to ensure that only one of the two functions in the func tuple is satisfied:

from functools import reduce
tuple(filter(lambda x: reduce(bool.__xor__, map(lambda f: f(x), func)), data))

This returns:

(2, 5, 7, 9)

Upvotes: 0

Related Questions