filter
只接受一个迭代,而 map
接受一个可变数量的迭代数。例如,我可以用尽 map(operator.add, [1, 2, 3, 4], [1, 2, 2, 4])
以获得 [2, 4, 5, 8]
.
我正在寻找一个类似的机制,用于 filter
,接受任何谓词和可变数量的迭代词。用尽 filter(operator.eq, [1, 2, 3, 4], [1, 2, 2, 4])
引起 TypeError
关于如何 filter
只接受1个iterable,而不是2个。
对于这种特殊情况,我的预期输出是 ([1, 2, 4], [1, 2, 4])
即不满足以下条件的配对元素 operator.eq
被删除。
这是我目前所拥有的(急切版本只支持2个迭代项而不是N个)。
from typing import TypeVar, Callable, Iterable
A = TypeVar("A")
B = TypeVar("B")
def filter_(predicate: Callable[[A, B], bool], iterable1: Iterable[A], iterable2: Iterable[B]) -> (Iterable[A], Iterable[B]):
filtered_iterable1 = []
filtered_iterable2 = []
for value1, value2 in zip(iterable1, iterable2):
if predicate(value1, value2):
filtered_iterable1.append(value1)
filtered_iterable2.append(value2)
return filtered_iterable1, filtered_iterable2
然而我的目标是:1)能够支持N个迭代词,2)能够有 filter_
不急不躁 filter
.
怎么样。
def filter_(predicate, *iterables):
for t in zip(*iterables):
if predicate(*t):
yield t
print(list(filter_(operator.eq, [1, 2, 3, 4], [1, 2, 2, 4])))
它是懒惰的,它输出 [(1, 1), (2, 2), (4, 4)]
为您的测试用例,不,您不能使用 ([1, 2, 4], [1, 2, 4])
因此,以一种懒惰的方式。要从 [(1, 1), (2, 2), (4, 4)]
到 ([1, 2, 4], [1, 2, 4])
你可以用。zip(*filter_(operator.eq, [1, 2, 3, 4], [1, 2, 2, 4]))
但这样一来,你就失去了懒惰的感觉。
遗憾的是没有等价的 starmap
喜欢 starfilter
所以我能想到的等价物是:
[i for i in zip(*lists) if predicate(*i)]
lists
这里的意思是... ([..], [..])
. 这将导致。
[(1, 1), (2, 2), (4, 4)]
要想把它变回单独的列表,使用 tuple(map(list, zip(*result)))
:
([1, 2, 4], [1, 2, 4])
所以,把它放在一起。
predicate = operator.eq
lists = [1, 2, 3, 4], [1, 2, 2, 4]
result = tuple(map(list, zip(*(i for i in zip(*lists) if predicate(*i)))))
你的答案在你的执行过程中。Map 接受一个函数,接受多个列表,而这些列表必须与参数的数量相匹配。Filter只接受一个列表来进行过滤,所以两者的区别不仅仅是语义上的--filter只接受一个列表是合理的。在你的例子中,列表确实是 zip
这就是你要实现的。你缺少的是一个巧妙的方法来解除配对的结果。
>>> r1, r2 = zip(*filter(lambda x: predicate(*x), zip([1, 2, 3, 4, 5], [1, 1, 3, 3, 5)))
>>> r1
(1, 3, 5)
>>> r2
(1, 3, 5)