Python:在列表中查找


583

我遇到了这个:

item = someSortOfSelection()
if item in myList:
    doMySpecialFunction(item)

但有时它不适用于我的所有物品,好像它们在列表中没有被识别(当它是字符串列表时)。

这是在列表中查找项目的最“ pythonic”方式if x in l:吗?


3
很好,并且如果item等于里面的元素之一应该可以工作myList
Niklas B.

1
您的意思是做事的好方法吗?在我的几次试验中,也许有空格,并且换行符inreferrefering ...我只是想确定这是实施“在列表中查找”的好方法(一般而言)
Stephane Rolland 2012年

Answers:


1173

关于您的第一个问题:该代码非常好,并且如果与item其中的一个元素相等就应该可以工作myList。也许您尝试找到与其中一项不完全匹配的字符串,或者您使用的浮点值会导致不正确。

至于第二个问题:如果“查找”列表中的内容,实际上有几种可能的方法。

检查里面是否有东西

这是您描述的用例:检查列表中是否包含某些内容。如您所知,您可以使用in运算符:

3 in [1, 2, 3] # => True

过滤集合

即,找到满足特定条件的序列中的所有元素。您可以为此使用列表推导或生成器表达式:

matches = [x for x in lst if fulfills_some_condition(x)]
matches = (x for x in lst if x > 6)

后者将返回一个生成器,您可以将其想象为一种懒惰列表,该列表只有在您对其进行迭代时才会被构建。顺便说一句,第一个完全等于

matches = filter(fulfills_some_condition, lst)

在Python 2中。在这里您可以看到工作中的高阶函数。在Python 3中,filter不返回列表,而是返回类似生成器的对象。

寻找第一次出现

如果您只想匹配条件的第一件事(但是您还不知道它是什么),那么可以使用for循环(可能也使用该else子句,这并不是很知名)。您也可以使用

next(x for x in lst if ...)

StopIteration如果没有找到任何匹配项,则将返回第一个匹配项或引发a 。或者,您可以使用

next((x for x in lst if ...), [default value])

查找物品的位置

对于列表,index如果您想知道某个元素在列表中的何处,还有一种方法有时会很有用:

[1,2,3].index(2) # => 1
[1,2,3].index(4) # => ValueError

但是,请注意,如果有重复项,则.index始终返回最低索引:......

[1,2,3,2].index(2) # => 1

如果有重复项,并且想要所有索引,则可以enumerate()改用:

[i for i,x in enumerate([1,2,3,2]) if x==2] # => [1, 3]

10
史蒂芬:让我重组你的问题:if x in list不是人们抱怨不是一个内置功能的东西。他们抱怨以下事实:没有明确的方法可以找到列表中符合特定条件的事物的首次出现。但是,正如我的回答中所述,next()可以被滥用。
Niklas B.

3
@Stephane:第二个不是生成元组,而是生成器(基本上是一个尚未构建的列表)。如果只想使用一次结果,通常最好使用生成器。但是,如果要在以后多次使用创建的集合,则建议首先创建一个显式列表。看看我的更新,现在它的结构更好了:)
Niklas B.

26
您的“发现第一次出现”的例子是黄金。感觉比[list comprehension...][0]方法更具Python风格
13年

4
我对python的“功能”功能越来越失望。在haskell中,Data.List模块中有find函数正是这样做的。但是在python中不是,并且将其缩小为库很小,因此您必须一次又一次地重新实现相同的逻辑。真是浪费……
user1685095 '16

3
这将是很好,如果有一个kwarg来index()key那个忙得key所接受max(); 例如:index(list, key=is_prime)
Curt

189

如果要查找一个元素或在中None使用default next,则StopIteration在列表中未找到该元素时不会提高:

first_or_default = next((x for x in lst if ...), None)

1
next将迭代器作为第一个参数,而列表/元组不是迭代器。所以应该first_or_default = next(iter([x for x in lst if ...]), None)docs.python.org/3/library/functions.html#next
Devy 2016年

7
@Devy:是的,但是(x for x in lst if ...)是列表上的一个生成器lst(它一个迭代器)。如果这样做next(iter([x for x in lst if ...]), None),则必须构造list [x for x in lst if ...],这将是更加昂贵的操作。
Erlend Graff

1
这里有一个抽象来定义查找功能。只需将的布尔表达式封装if在lambda中,就可以编写find(fn,list)代码而不是混淆生成器代码。
2015年

22

虽然Niklas B.的答案非常全面,但是当我们想在列表中查找某项时,有时获得其索引很有用:

next((i for i, x in enumerate(lst) if [condition on x]), [default value])

11

寻找第一次出现

在其中有一个配方itertools

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

例如,以下代码查找列表中的第一个奇数:

>>> first_true([2,3,4,5], None, lambda x: x%2==1)
3  

6

另一种选择:您可以使用来检查项目是否在列表中if item in list:,但这是订单O(n)。如果您要处理大量项目,而您只需要知道某项是否是列表的成员,则可以先将列表转换为集合,然后利用恒定时间集查找

my_set = set(my_list)
if item in my_set:  # much faster on average than using a list
    # do something

并非在每种情况下都是正确的解决方案,但是在某些情况下,这可能会为您带来更好的性能。

请注意,使用来创建集合set(my_list)也是O(n),因此,如果您只需要执行一次此操作,则以这种方式进行操作不会更快。但是,如果您需要反复检查成员资格,则在初始集创建之后,每次查找将为O(1)。


4

在处理字符串列表时,您可能想使用两种可能的搜索之一:

  1. 如果list元素等于一个项目('example'在['one','example','two']中):

    if item in your_list: some_function_on_true()

    ['one','ex','two']中的'ex'=>真

    ['one','ex','two']中的'ex_1'=>否

  2. 如果list元素就像一个项目(“ ex”在['one,'example','two']中,或者'example_1'在['one','example','two']中):

    matches = [el for el in your_list if item in el]

    要么

    matches = [el for el in your_list if el in item]

    然后只需要检查len(matches)或阅读即可。


3

定义和用法

count()方法返回具有指定值的元素数。

句法

list.count(value)

例:

fruits = ['apple', 'banana', 'cherry']

x = fruits.count("cherry")

问题的例子:

item = someSortOfSelection()

if myList.count(item) >= 1 :

    doMySpecialFunction(item)

2
这在很长的列表中有效吗?说一百万的清单?
3kstc

1
我不确定 !!!
josef

1

而不是使用的list.index(x)如果在列表中找到返回x的指数或返回#ValueError,如果没有找到X,你可以使用邮件list.count(x)返回列表x的发生次数(验证x是确实在列表中),或者它否则返回0(在没有x的情况下)。有趣的count()是,它不会破坏您的代码,也不会要求您在找不到x时抛出异常


不好的是它很重要。找到元素时它不会停止。所以性能上的大名单坏
让·弗朗索瓦·法布尔

1

如果您要检查一次收藏品中是否存在值,则可以使用“ in”运算符。但是,如果要检查一次以上,则建议使用bisect模块。请记住,使用bisect模块的数据必须进行排序。因此,您可以对数据进行一次排序,然后可以使用二等分。在我的机器上使用bisect模块比使用“ in”运算符快12倍。

这是使用Python 3.8及更高版本语法的代码示例:

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value
    )

data = list(range(1000))
# value to search
true_value = 666
false_value = 66666

# times to test
ttt = 1000

print(f"{bisect_search(data, true_value)=} {bisect_search(data, false_value)=}")

t1 = timeit(lambda: true_value in data, number=ttt)
t2 = timeit(lambda: bisect_search(data, true_value), number=ttt)

print("Performance:", f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

输出:

bisect_search(data, true_value)=True bisect_search(data, false_value)=False
Performance: t1=0.0220, t2=0.0019, diffs t1/t2=11.71

0

检查字符串列表中的项目是否没有其他多余的空格。这就是可能无法解释项目的原因。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.