使用地图和过滤器等效的列表理解

时间:2019-04-14 15:31:58

标签: python python-3.x list list-comprehension map-function

我想使用地图和/或过滤器功能编写此代码。如果总和达到目标,它将返回列表中项目的索引

我已经使用列表理解了,但是看不到如何将第二个for循环添加到map / filter函数中。我不确定要使用的语法,如果我为map / filter函数的函数参数定义自己的函数

num = [2,5,7,11,6,15,3,4]
tgt= 9
[num.index(x) for x in num for y in num if x + y == tgt]

结果:

[0, 1, 2, 4, 6, 7]

4 个答案:

答案 0 :(得分:5)

由于filtermap都按顺序处理单个项目,因此您必须从列表中每个项目而不是项目组合的角度查看逻辑。意味着您需要将列表理解中使用的表达式重新表述为单个项目的功能。因此,将其视为x + y == tgt(而不是过滤条件x == tgt - y)是有益的,其中y也必须是num列表中的一项,以便您列表理解可以重写为:

[num.index(x) for x in num if x in {tgt - y for y in num}]

通过这种等效的列表理解,可以清楚地看到,要实现过滤条件,需要通过将num中的每个项目映射到其与tgt的差异来建立一个集合,可以使用tgt.__sub__方法,并测试x中的每个项目num是否是集合的成员,这可以通过集合的__contains__方法完成,最后,映射过滤后的序列到num.index,以输出每个匹配项的索引:

list(map(num.index, filter(set(map(tgt.__sub__, num)).__contains__, num)))

这将返回:

[0, 1, 2, 4, 6, 7]

答案 1 :(得分:0)

双循环可以被编码为itertools.product

>>> list(map(lambda x: num.index(x[0]), filter(lambda x: sum(x) == tgt, itertools.product(num, num))))
[0, 1, 2, 4, 6, 7]

让我们砍代码:

filter(lambda x: sum(x) == tgt, itertools.product(num, num))

itertools.product返回一个元组的迭代器,其中元组中的元素为(x, y),类似于您使用的嵌套循环。 在我们过滤掉那些元组的总和等于tgt的情况下,在这里使用sum是更好的选择,但请注意,它与x[0] + x[1]相同(请记住,我们给{ {1}})。

一旦进行了过滤,我们将应用保留功能(2, 2)的每个元组,因为我们有元组,我们只需要使用其中一个值,请记住第一个匹配嵌套的for循环{{ 1}}因此是num.index

答案 2 :(得分:0)

试试看!您可以使用itertools.product来获取两者的组合。然后过滤总和为tgt的项目的组合列表。然后将lambda映射到这些结果,以获取这些组合中第一项的索引。

list(map(lambda x: num.index(x[0]), (filter(lambda x: sum(x) == tgt, itertools.product(num, repeat=2)))))

答案 3 :(得分:0)

反复调用num.index效率很低。每次找到满足条件的数字时,对index的调用都需要顺序扫描列表。

相反,请循环遍历列表中的索引。通过对数组建立索引(随机访问)进行比较,这将更加高效。

正如其他人指出的那样,您可以使用itertools.product,但可以使用num的自乘积代替range(len(num))的乘积。

使用mapfilter

from operator import itemgetter
from itertools import product

res = map(
    itemgetter(0), 
    filter(
        lambda c: num[c[0]]+num[c[1]] == tgt, 
        product(range(len(num)),range(len(num)))
    )
)
print(list(res))
#[0, 1, 2, 4, 6, 7]

内部filter正在过滤介于0和num的长度减一之间的所有数字对,对于这些数字,在那些相应索引处num的值等于目标。由于product返回一对索引,而您只对第一个值感兴趣,因此将mapfilter的结果itemgetter(0)一起获得第一个元素。

更紧凑地理解列表:

[i for i, j in product(range(len(num)), range(len(num))) if num[i] + num[j] == tgt]