我有一个两项列表的列表,需要搜索其中的内容.
如果列表是:
list =[ ['a','b'], ['a','c'], ['b','d'] ]
Run Code Online (Sandbox Code Playgroud)
我可以轻松地搜索一对
['a','b'] in list
Run Code Online (Sandbox Code Playgroud)
现在,有没有办法看看我是否有一对在第二个位置存在字符串?我可以做这个:
for i in range (0, len(list)):
if list[i][1]==search:
found=1
Run Code Online (Sandbox Code Playgroud)
但是没有for循环是否有更好的方法?我i发现它不需要知道或保持循环.
Dav*_*d Z 72
这是Pythonic的方法:
data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
any(e[1] == search for e in data)
Run Code Online (Sandbox Code Playgroud)
或者......好吧,我不会声称这是"一种真正的Pythonic方式",因为在某些时候它变得有点主观,什么是Pythonic,什么不是,或者哪种方法比Pythonic更多另一个.但是,使用any()肯定更典型的Python风格比for环路中如RichieHindle的回答,
当然,在实现中有一个隐藏循环any,尽管它一找到匹配就会突然出现循环.
由于我很无聊,我制作了一个计时脚本来比较不同建议的性能,并根据需要修改其中的一些以使API相同.现在,我们应该记住,最快并不总是最好的,快速绝对不是Pythonic.话虽如此,结果......很奇怪.显然for循环速度非常快,这不是我所期望的,所以我不知道为什么他们会以他们的方式出现这些东西.
无论如何,当我使用问题中定义的列表时,每个子列表包含两个元素,从最快到最慢,我得到以下结果:
for环路,时钟频率为0.22μsfor循环相关,为0.48μsoperator.itemgetter(),为0.53μsifilter()和匿名的回答,在0.67微秒(Alex的持续大约半微秒快)any(),全部进入0.81-0.82μs显然,实际时间对任何其他人的硬件都没有意义,但是它们之间的差异应该让人知道不同方法的接近程度.
当我使用更长的列表时,事情会有所改变.我从问题列表开始,有三个子列表,并附加了另外197个子列表,总共有200个子列表,每个子列表长度为2.使用这个更长的列表,结果如下:
operator.itemgetter()再次使用0.53μsifilter()和匿名的回答,在0.67微秒any(),全部以0.81-0.82μs进入这些是在列表扩展时保持原始时间的那些.其余的,没有,是
for来自原始问题的循环,为1.24μsRic*_*dle 42
你总是会有一个循环 - 有人可能会带来一个聪明的单行,在一个map()或类似的呼叫中隐藏循环,但它总是会在那里.
除非性能是一个主要因素,否则我总是希望拥有干净简单的代码.
这可能是你的代码的更Pythonic版本:
data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
for sublist in data:
if sublist[1] == search:
print "Found it!", sublist
break
# Prints: Found it! ['a', 'c']
Run Code Online (Sandbox Code Playgroud)
一旦找到匹配,它就会突破循环.
(顺便说一句,你有一个错字['b''d'].)
Bra*_*lor 16
>>> the_list =[ ['a','b'], ['a','c'], ['b''d'] ]
>>> any('c' == x[1] for x in the_list)
True
Run Code Online (Sandbox Code Playgroud)
Ter*_*les 14
以上都很好看
但是你想保留结果吗?
如果是这样...
你可以使用以下
result = [element for element in data if element[1] == search]
Run Code Online (Sandbox Code Playgroud)
那么简单
len(result)
Run Code Online (Sandbox Code Playgroud)
让你知道是否找到了任何东西(现在你可以用结果做事)
当然这不会处理长度小于1的元素(除非你知道它们总是大于长度1,否则你应该检查它们,在这种情况下你应该使用元组吗?(元组是不可变的))
如果您知道所有项目都是设定长度,您还可以:
any(second == search for _, second in data)
Run Code Online (Sandbox Code Playgroud)
或者对于len(data [0])== 4:
any(second == search for _, second, _, _ in data)
Run Code Online (Sandbox Code Playgroud)
......我建议使用
for element in data:
...
Run Code Online (Sandbox Code Playgroud)
代替
for i in range(len(data)):
...
Run Code Online (Sandbox Code Playgroud)
(为了将来的使用,除非你想保存或使用'i',并且只是因为你知道不需要'0',你只需要使用完整的语法,如果你从非零值开始)
>>> my_list =[ ['a', 'b'], ['a', 'c'], ['b', 'd'] ]
>>> 'd' in (x[1] for x in my_list)
True
Run Code Online (Sandbox Code Playgroud)
编辑添加:
两个大卫的回答使用任何和我用在将结束时,他们找到匹配的,因为我们使用生成器表达式.这是一个使用无限生成器的测试来表明:
def mygen():
''' Infinite generator '''
while True:
yield 'xxx' # Just to include a non-match in the generator
yield 'd'
print 'd' in (x for x in mygen()) # True
print any('d' == x for x in mygen()) # True
# print 'q' in (x for x in mygen()) # Never ends if uncommented
# print any('q' == x for x in mygen()) # Never ends if uncommented
Run Code Online (Sandbox Code Playgroud)
我只是喜欢使用in而不是==和any.
关于什么:
list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'b'
filter(lambda x:x[1]==search,list)
Run Code Online (Sandbox Code Playgroud)
这将返回列表列表中的每个列表,第二个元素等于search.
Markus有一种避免使用该词的方法for-这是另一种方法,长期使用应该具有更好的性能the_list:
import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)
Run Code Online (Sandbox Code Playgroud)