2013-03-13 78 views
3

我想要从子列表的整数值含“B”为第一要素(B将只在列表中出现一次)的Python:列表理解与拉姆达

这两种方式来到我的脑海:

foo = [["a", 5], ["b", 10], ["c", 100]] 

y = filter(lambda x: x[0] == "b", foo) 
print y[0][1] 

z = [foo[i][1] for i in range(len(foo)) if foo[i][0] == "b"] 
print z[0] 

他们都工作。有两个更好的选择(关于运行时),还有更好的第三种方式吗?

+1

'z = [x [1] for x in foo if x [0] =='b']'even even even more clean。 – glormph 2013-03-13 11:32:28

+1

或'[b for a,b in foo if a =='b']''。 – 2013-03-13 11:36:21

回答

10

当名单很小时,两者之间没有显着差异。如果输入列表可能变大,则会出现更严重的问题:您正在迭代整个列表,而您可能会停在第一个元素上。你可以用一个循环做到这一点,但如果你想使用一个修真类的语句,来这里生成器表达式

# like list comprehensions but with() instead of [] 
gen = (b for a, b in foo if a == 'b') 
my_element = next(gen) 

或者干脆:

my_element = next(b for a, b in foo if a == 'b') 

如果您想了解有关发电机表达式的更多信息,请参阅PEP 289


请注意,即使使用生成器和迭代器,您也有多个选择。

from itertools import ifilter 

my_element = next(ifilter(lambda (x, y): x == 'b', foo)) 

我个人不喜欢这样做,因为它的可读性差得多,但如果这是您的问题,那可能会更快。

无论如何,如果您需要对您的代码进行基准测试,我推荐使用the timeit module

+1

'next(v for k,v in foo if k ==“b”)''使用next()而不是'.next()' - 更向前兼容。 – DSM 2013-03-13 11:41:09

+0

谢谢,更新了答案。 – 2013-03-13 11:43:07

+0

在我的计时中,如果必须检查两个以上的项目,“ifilter”版本会丢失。 – 2013-03-13 12:37:01

3

这比达维德的答案(我计时吧)慢,但具有简单的优点:

z = dict(foo)['b'] 

当然它假定你的钥匙都是可哈希的,但如果是字符串的罚款。 如果你需要做多个查找,虽然这绝对是要走的路(只要确保只转换为字典一次)。

+0

+1为简单起见,但我不认为这会加快速度,因为它需要对序列进行完整的迭代。如果速度是问题,我会基准(和配置文件),因为它取决于许多事情(列表的大小,内存要求,散列冲突)取决于输入。 – 2013-03-13 11:53:00

+0

@DavideR。我对它进行了计时,对于列表多达约10,000个元素,如果它是最后一个元素或平均速度的两倍,则解决方案的速度大约相同。对于一个100,000个元素列表,您平均可以快4倍。 – Duncan 2013-03-13 12:03:56