【问题标题】:Equivalent of List Comprehension Using Map and Filter使用 Map 和 Filter 的列表理解的等价物
【发布时间】:2019-04-14 15:31:58
【问题描述】:

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

我已经为此使用了列表推导,但看不到如何将第二个 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]

【问题讨论】:

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


    【解决方案1】:

    由于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__ 完成方法,并测试num中的每一项x是否是集合的成员,这可以通过集合的__contains__方法完成,最后将过滤后的序列映射到num.index以输出索引每个匹配项:

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

    这会返回:

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

    【讨论】:

    • 在此处使用set 而不是list list(map(tgt.__sub__, num)) 以获得更好的查找效果
    • @blhsing 你能解释一下你的解决方案的内部工作原理吗?
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      双循环可以编码为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 返回一个元组迭代器,其中包含 num 中的元素,(x, y) 类似于您使用的嵌套循环。 我们过滤哪些元组总和等于tgt,在这里使用sum 是更好的选择,但请注意它与x[0] + x[1] 相同(请记住,我们将像(2, 2) 这样的元组提供给该函数) .

      一旦我们过滤了这些元组,我们就会为每个保留函数num.index的元组申请,因为我们有元组,我们只需要使用其中一个值,记住第一个匹配嵌套的for循环x因此num.index(x[0])

      【讨论】:

      • 谢谢你能解释一下内部工作原理。为什么要使用归约函数,即( sum() 和 product() )和 num.index(x[0]) ?
      【解决方案4】:

      反复调用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 返回一对索引并且您只对第一个值感兴趣,因此 mapfilteritemgetter(0) 的结果得到第一个元素。

      更紧凑的列表理解:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-02
        • 2018-01-25
        • 1970-01-01
        • 1970-01-01
        • 2013-02-25
        相关资源
        最近更新 更多