Python搜索列表列表

gre*_*eye 52 python list

我有一个两项列表的列表,需要搜索其中的内容.

如果列表是:

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循环速度非常快,这不是我所期望的,所以我不知道为什么他们会以他们的方式出现这些东西.

无论如何,当我使用问题中定义的列表时,每个子列表包含两个元素,从最快到最慢,我得到以下结果:

  1. RichieHindle的回答for环路,时钟频率为0.22μs
  2. Terence Honles的第一个建议是创建一个0.36μs的列表
  3. Pierre-Luc Bedard的答案(最后一个代码块),为0.43μs
  4. 基本上与Markus的答案原始问题for循环相关,为0.48μs
  5. Coady的答案使用operator.itemgetter(),为0.53μs
  6. 足够接近算作之间的粘结亚历马尔泰利的答案ifilter()匿名的回答,在0.67微秒(Alex的持续大约半微秒快)
  7. 另一个与jojo的答案之间存在足够紧密的关系,我的,Brandon E Taylor(与我的相同)和Terence Honles的第二个建议使用any(),全部进入0.81-0.82μs
  8. 然后user27221的答案使用嵌套列表推导,为0.95μs

显然,实际时间对任何其他人的硬件都没有意义,但是它们之间的差异应该让人知道不同方法的接近程度.

当我使用更长的列表时,事情会有所改变.我从问题列表开始,有三个子列表,并附加了另外197个子列表,总共有200个子列表,每个子列表长度为2.使用这个更长的列表,结果如下:

  1. RichieHindle的答案与缩短列表的0.22μs相同
  2. Coady的回答operator.itemgetter()再次使用0.53μs
  3. Terence Honles的第一个建议是创建一个0.36μs的列表
  4. 之间的另一个虚拟联络亚历克斯·马尔泰利的答案ifilter()匿名的回答,在0.67微秒
  5. 我的答案,布兰登·E·泰勒的相同方法和特伦斯·霍勒斯的第二个建议使用之间的关系再次紧密相关any(),全部以0.81-0.82μs进入

这些是在列表扩展时保持原始时间的那些.其余的,没有,是

  1. for来自原始问题的循环,为1.24μs
  2. Terence Honles的第一个建议是创建一个列表,为7.49μs
  3. Pierre-Luc Bedard的答案(最后一个代码块),为8.12μs
  4. Markus的答案是10.27μs
  5. JoJo的答案,在19.87微秒
  6. 最后,user27221的答案使用嵌套列表推导,为60.59μs


Ric*_*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'].)

  • @ Chris-Jr:将`if sublist [1] == search`替换为`if search in sublist`. (2认同)

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',你只需要使用完整的语法,如果你从非零值开始)


Ano*_*non 9

>>> 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.


joj*_*ojo 7

关于什么:

list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'b'

filter(lambda x:x[1]==search,list)
Run Code Online (Sandbox Code Playgroud)

这将返回列表列表中的每个列表,第二个元素等于search.


Ale*_*lli 5

Markus有一种避免使用该词的方法for-这是另一种方法,长期使用应该具有更好的性能the_list

import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)
Run Code Online (Sandbox Code Playgroud)