Python搜索列表列表

时间:2009-07-20 21:34:26

标签: python list

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

如果列表是:

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

我可以通过

轻松搜索一对
['a','b'] in list

现在,有没有办法看看我是否有一对在第二个位置存在字符串?我可以这样做:

for i in range (0, len(list)):
    if list[i][1]==search:
       found=1

但是没有for循环会有更好的方法吗?我不需要知道i或者在找到它之后继续循环。

13 个答案:

答案 0 :(得分:68)

这是Pythonic的方法:

data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
any(e[1] == search for e in data)

或者......好吧,我不会声称这是“一种真正的Pythonic方式”,因为在某些时候它变得有点主观,什么是Pythonic,什么不是,或者哪种方法是Pythonic比另一个更多。但是使用any()肯定是比for循环更典型的Python样式,例如RichieHindle's answer

当然在any的实现中有一个隐藏循环,尽管它一找到匹配就会突破循环。


由于我很无聊,我制作了一个计时脚本来比较不同建议的性能,并根据需要修改其中一些建议以使API相同。现在,我们应该记住,最快并不总是最好的,快速绝对不是Pythonic。话虽如此,结果......很奇怪。显然for循环速度非常快,这不是我所期望的,所以我会不加理解为什么他们会像他们那样出现。

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

    带有for循环的
  1. RichieHindle's answer,时钟频率为0.22μs
  2. Terence Honles' first suggestion创建一个列表,为0.36μs
  3. Pierre-Luc Bedard's answer (last code block),0.43μs
  4. 基本上绑定在Markus's answer和来自the original questionfor循环之间,为0.48μs
  5. Coady's answer使用operator.itemgetter(),0.53μs
  6. 足够接近,可以算作Alex Martelli's answerifilter()Anon's answer之间的平局,为0.67μs(Alex的速度一直快约半微秒)
  7. jojo's answer,我的Brandon E Taylor's(与我的相同)和使用any()的{​​{3}}之间的另一个足够紧密的关系,全部以0.81-0.82进入微秒
  8. 然后Terence Honles' second suggestion使用嵌套列表推导,0.95μs
  9. 显然,实际时间对其他人的硬件没有意义,但是它们之间的差异应该让我们知道不同方法的接近程度。

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

    1. user27221's answer,与短名单相同的0.22μs
    2. RichieHindle's answer使用operator.itemgetter(),再次使用0.53μs
    3. Coady's answer创建一个列表,为0.36μs
    4. Terence Honles' first suggestionifilter()Alex Martelli's answer之间的另一个虚拟联系,为0.67μs
    5. 我的回答,Anon's answer相同的方法与使用any()的{​​{3}}之间的关系足够紧密,全部以0.81-0.82μs进行
    6. 这些是在列表扩展时保持原始时间的那些。其余的,没有,是

      1. 来自Brandon E Taylor'sfor循环,为1.24μs
      2. Terence Honles' second suggestion以7.49μs
      3. 创建列表
      4. the original question,8.12μs
      5. Terence Honles' first suggestion,10.27μs
      6. Pierre-Luc Bedard's answer (last code block),19.87μs
      7. 最后Markus's answer使用嵌套列表推导,为60.59μs

答案 1 :(得分:39)

你总是会有一个循环 - 有人可能会带来一个聪明的单行,在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']

一旦找到匹配就会中断循环。

(顺便说一下,你在['b''d']中有一个拼写错误。)

答案 2 :(得分:16)

>>> the_list =[ ['a','b'], ['a','c'], ['b''d'] ]
>>> any('c' == x[1] for x in the_list)
True

答案 3 :(得分:13)

以上都很好看

但你想保留结果吗?

如果是的话......

您可以使用以下

result = [element for element in data if element[1] == search]

然后一个简单的

len(result)

告诉您是否找到了任何内容(现在您可以对结果进行处理)

当然这不会处理长度小于1的元素 (你应该检查,除非你知道他们总是大于 长度1,在这种情况下你应该使用元组吗? (元组是不可变的))

如果您知道所有项目都是设定长度,您也可以这样做:

any(second == search for _, second in data)

或len(data [0])== 4:

any(second == search for _, second, _, _ in data)

......我建议使用

for element in data:
   ...

而不是

for i in range(len(data)):
   ...

(供将来使用,除非你想保存或使用'我',只是让你知道 '0'不是必需的,如果你正在启动,你只需要使用完整的语法 在非零值)

答案 4 :(得分:9)

>>> my_list =[ ['a', 'b'], ['a', 'c'], ['b', 'd'] ]
>>> 'd' in (x[1] for x in my_list)
True

编辑添加:

大卫使用任何的答案以及我在中使用的答案都将在找到匹配项后结束,因为我们正在使用生成器表达式。这是一个使用无限生成器来测试的测试:

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

我只想使用 而不是 == 任何

答案 5 :(得分:6)

怎么样:

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

filter(lambda x:x[1]==search,list)

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

答案 6 :(得分:4)

马库斯有一种避免使用单词for的方法 - 这是另一种方法,对于长the_list来说应该有更好的表现......:

import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)

答案 7 :(得分:3)

使用gen exp没有错,但如果目标是内联循环......

>>> import itertools, operator
>>> 'b' in itertools.imap(operator.itemgetter(1), the_list)
True

也应该是最快的。

答案 8 :(得分:2)

k旧帖子但没有人使用列表表达式来回答:P

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

# return if it find in either item 0 or item 1
print [x for x,y in list if x == Search or y == Search]

# return if it find in item 1
print [x for x,y in list if y == Search]

答案 9 :(得分:1)

>>> the_list =[ ['a','b'], ['a','c'], ['b','d'] ]
>>> "b" in zip(*the_list)[1]
True

zip()通过索引将一堆列表和组元素放在一起,有效地转换列表列表矩阵。星号采用the_list的内容并将其作为参数发送给zip,因此您可以有效地分别传递三个列表,这是zip想要的。剩下的就是检查列表中是否"b"(或其他)是否包含您感兴趣的索引元素。

答案 10 :(得分:1)

我在寻找字典的深层发现,但没有找到。根据本文,我能够创建以下内容。谢谢,享受!!

def deapFind( theList, key, value ):
    result = False
    for x in theList:
        if( value == x[key] ):
            return True
    return result

theList = [{ "n": "aaa", "d": "bbb" }, { "n": "ccc", "d": "ddd" }]
print 'Result: ' + str (deapFind( theList, 'n', 'aaa'))

我使用==代替in运算符,因为in对部分匹配返回true。 IOW:在n键上搜索aa将返回true。我不希望那样。

HTH

答案 11 :(得分:0)

我认为使用嵌套列表推导是解决此问题的最优雅方法,因为中间结果是元素所在的位置。实施将是:

list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'c'
any([ (list.index(x),x.index(y)) for x in list for y in x if y == search ] )

答案 12 :(得分:-1)

以下是一种简单的方法,可以准确找到项目列表中的位置。

for i in range (0,len(a)):
sublist=a[i]
for i in range(0,len(sublist)):
    if search==sublist[i]:
        print "found in sublist "+ "a"+str(i)