2014-01-17 52 views
1

我有一个基本的“餐巾纸算法”,它采用元组列表(2项)并更改它们。这是英文:python优化函数没有循环

  1. 如果项目2是一个列表,改变第1项是串x
  2. 以其他方式改变第1项是y字符串

这里是一个快速功能我把一起这样做:

def f(objects): 
    list_type = "string_x" 
    other = "string_y" 
    hold = [] 
    for x in objects: 
     if isinstance(x[1],list): 
      hold.append((list_type,x[1])) 
     else: 
      hold.append((other,x[1])) 
    return hold 

我不认为这是最有效的方式。这个算法非常简单,只是一个基本的陈述。 这样做会更有效吗?

+0

灿你举了一个你作为'objects'传递的例子吗? – brandonscript

+3

“高效”是指“快速”还是“可读”或其他不同?是什么让你觉得它效率不高? – abarnert

+2

无论你如何去做,地图,列表理解或其他,它必须是*某种排序*循环 – yuvi

回答

2

你可以让这一点通过使用if表达短:

def f(objects): 
    list_type = "string_x" 
    other = "string_y" 
    hold = [] 
    for x in objects: 
     hold.append((list_type if isinstance(x[1], list) else other, x[1])) 
    return hold 

然后很容易变成理解,它更短,可能更易读,更快一些:*

def f(objects): 
    list_type = "string_x" 
    other = "string_y" 
    return [(list_type if isinstance(x[1], list) else other, x[1]) 
      for x in objects] 

真的,我不知道那些局部变量是使事情更清楚:**

def f(objects): 
    return [("string_x" if isinstance(x[1], list) else "string_y", x[1]) 
      for x in objects] 

同时,如果你要与返回的列表做的唯一事情就是迭代(例如,因为这只是转换链中的一个),你根本不应该返回一个列表。无论是yield每个值,返回genexpr而不是listcomp,或者(如果你有Python的3.3+)获得两全其美:

def f(objects): 
    yield from (("string_x" if isinstance(x[1], list) else "string_y", x[1]) 
       for x in objects) 

*您还在做同样的循环,所以你有完全相同的算法复杂性。然而,循环和列表追加都是通过采用一些快捷方式的自定义字节码来实现的,这使得每次迭代更加高效。 (“自定义字节码”的细节当然具体到CPython的和其他的字节码兼容的实现比如PyPy,但在一般情况下,任何实现至少可能承担list解析快捷方式。)

**这最后很可能稍微快一点,因为它将常量加载到堆栈而不是本地变量。再次,它可能也有稍差的缓存局部性。如果真的很重要,请测试并看看。

+0

哇我不能相信我忘了你可以做,如果和其他在列表理解 –

+1

@RyanSaxe:“在列表理解”部分在这里并不真正相关;这是一个通用的表达式,你可以做任何表达式。 (对于最后的过滤子句,还有'if'的理解特定用法,但我没有在这里使用它。) – abarnert

+0

感谢您的澄清。当我被允许时,我会在10分钟内将此答案标记为正确 –

0

使用列表理解会更有效和Python的(如果我没看错):

[("string_x" if isinstance(x[1], list) else "string_y", x[1]) for x in objects] 
+0

你不能'映射'一个表达式,只能是一个函数。也许你想要一个列表理解?或''地图'与'lambda'? – abarnert

+0

固定。我对“地图”的痴迷。 –

0

如果你需要检查和更改列表中的所有项目,你需要一个循环,否则你不能这样做。

使用列表理解可以使其更快一点,这可以减少每个列表项的所有附加功能。

def f(objects): 
    return [('string_x',x[1]) if isinstance(x[1],list) else ('string_y',x[1]) for x in objects] 

但是,如果你使用的是大名单的性能差异才可以看到

0

我挺喜欢做这种方式,但我可能是一个愚蠢的人:

strings = 'string_x', 'string_y' 

[(strings[isinstance(x[1],list)], x[1]) for x in objects]