映射具有条件

时间:2016-02-10 08:39:21

标签: python string dictionary lambda

我正在尝试使用map来避免Python中的循环以获得更好的性能。我的代码是

 def fun(s):
      result = []
      for i in range(len(s)-1):
          if (s[i:i+2]=="ab"):
              result.append(s[:i]+"cd"+s[i+2:])
      return result

我对该功能的猜测是:

def fun(s):
      return map(lambda s : s[:i]+"cd"+s[i+2:] if s[i:i+2]=="ab", s)

但是,在这种情况下,我不知道如何将i与s关联...而且上面的函数在语法上是错误的。 有人可以帮忙吗?

----------------------------------------------- --------添加说明---------------------------------------- ---------------  很多人都很困惑我为什么这样做。这个想法只来自Python performance document(参见循环部分)和Guido's article。我只是在学习。

非常感谢@gboffi,完美而又整洁的答案!

2 个答案:

答案 0 :(得分:1)

可能的解决方案

我用两个辅助定义编写了这个函数,但是如果你想要的话你可以把它写成一个衬里,

def fun(s):
    substitute = lambda i: s[:i]+'cd'+s[i+2:]
    match = lambda i: s[i:i+2]=='ab'
    return map(substitute, filter(match, range(len(s)-1)))

它的工作原理是使用s[i:i+2]创建'ab'匹配filter的索引列表,并仅为匹配的索引映射字符串替换函数。

计时

很明显,由于在每次调用时编译lambdas都会产生很大的开销,但幸运的是很容易测试这个hypotesis

In [41]:  def fun(s):
    result = []
    for i in range(len(s)-1):
        if (s[i:i+2]=="ab"):
            result.append(s[:i]+"cd"+s[i+2:])
    return result
   ....: 

In [42]: def fun2(s):
    substitute = lambda i: s[:i]+'cd'+s[i+2:]
    match = lambda i: s[i:i+2]=='ab'
    return map(substitute, filter(match, range(len(s)-1)))
   ....: 

In [43]: %timeit fun('aaaaaaabaaaabaaabaaab')
100000 loops, best of 3: 2.38 µs per loop

In [44]: %timeit fun2('aaaaaaabaaaabaaabaaab')
100000 loops, best of 3: 3.74 µs per loop

In [45]: %timeit fun('aaaaaaabaaaabaaabaaab'*1000)
10 loops, best of 3: 33.7 ms per loop

In [46]: %timeit fun2('aaaaaaabaaaabaaabaaab'*1000)
10 loops, best of 3: 33.8 ms per loop

In [47]: 

对于短字符串,map版本慢50%,而对于非常长的字符串,时间渐近相等......

答案 1 :(得分:0)

首先,我不认为地图比for循环具有性能优势。 如果's'很大,那么您可以使用xrange而不是范围https://docs.python.org/2/library/functions.html#xrange

第二张地图无法过滤元素,它只能将它们映射到新值。 您可以使用理解而不是for循环,但我认为您也不会获得性能优势。