在元组或对象列表上使用Python的list index()方法?

Rya*_*nch 53 python tuples list reverse-lookup

Python的列表类型有一个index()方法,它接受一个参数并返回匹配参数的列表中第一个项的索引.例如:

>>> some_list = ["apple", "pear", "banana", "grape"]
>>> some_list.index("pear")
1
>>> some_list.index("grape")
3
Run Code Online (Sandbox Code Playgroud)

是否有一种优雅(惯用)方式将其扩展到复杂对象列表,如元组?理想情况下,我希望能够做到这样的事情:

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> some_list.getIndexOfTuple(1, 7)
1
>>> some_list.getIndexOfTuple(0, "kumquat")
2
Run Code Online (Sandbox Code Playgroud)

getIndexOfTuple()只是一个假设的方法,它接受一个子索引和一个值,然后返回该子索引上具有给定值的列表项的索引.我希望

有没有办法实现这样的一般结果,使用列表推导或lambas或类似的"内联"?我想我可以编写自己的类和方法,但如果Python已经有办法,我不想重新发明轮子.

Pao*_*ino 65

这个怎么样?

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [x for x, y in enumerate(tuple_list) if y[1] == 7]
[1]
>>> [x for x, y in enumerate(tuple_list) if y[0] == 'kumquat']
[2]
Run Code Online (Sandbox Code Playgroud)

正如评论中指出的那样,这将获得所有匹配.要获得第一个,您可以:

>>> [y[0] for y in tuple_list].index('kumquat')
2
Run Code Online (Sandbox Code Playgroud)

评论中对于所有解决方案之间的速度差异进行了很好的讨论.我可能有点偏颇,但我会亲自坚持一个单行,因为我们谈论的速度相对于创建函数和导入模块来解决这个问题是非常微不足道的,但是如果你打算这么做很多您可能希望查看提供的其他答案的元素,因为它们比我提供的更快.

  • 仍然在内存中创建一个大小为 N 的新列表,这不是必需的。也在 O(n) 平均情况下运行,可以改进为 O(n/2)。是的,我知道这在技术上仍然是 O(n)。 (2认同)

Tri*_*ych 26

一段时间后,那些列表理解是混乱的.

我喜欢这种Pythonic方法:

from operator import itemgetter

def collect(l, index):
   return map(itemgetter(index), l)

# And now you can write this:
collect(tuple_list,0).index("cherry")   # = 1
collect(tuple_list,1).index("3")        # = 2
Run Code Online (Sandbox Code Playgroud)

如果您需要您的代码都具有超高性能:

# Stops iterating through the list as soon as it finds the value
def getIndexOfTuple(l, index, value):
    for pos,t in enumerate(l):
        if t[index] == value:
            return pos

    # Matches behavior of list.index
    raise ValueError("list.index(x): x not in list")

getIndexOfTuple(tuple_list, 0, "cherry")   # = 1
Run Code Online (Sandbox Code Playgroud)

  • +1作为超级高性能确实是发布的最快解决方案.我个人仍然会坚持使用一个班轮,因为这个级别的速度差异是毫无意义的,但无论如何都要知道. (2认同)

Jar*_*die 10

一种可能性是使用模块中的itemgetter函数operator:

import operator

f = operator.itemgetter(0)
print map(f, tuple_list).index("cherry") # yields 1
Run Code Online (Sandbox Code Playgroud)

调用itemgetter返回一个函数,该函数将foo[0]传递给传递给它的任何东西.map然后使用,将该函数应用于每个元组,将信息提取到新列表中,然后在其上index正常调用.

map(f, tuple_list)
Run Code Online (Sandbox Code Playgroud)

相当于:

[f(tuple_list[0]), f(tuple_list[1]), ...etc]
Run Code Online (Sandbox Code Playgroud)

这相当于:

[tuple_list[0][0], tuple_list[1][0], tuple_list[2][0]]
Run Code Online (Sandbox Code Playgroud)

这使:

["pineapple", "cherry", ...etc]
Run Code Online (Sandbox Code Playgroud)

  • Paolo提出了一个有趣的问题......正如我认为每个人都怀疑的那样,列表理解和枚举方法稍微快一点......在我那么科学的测试中超过100000次运行,枚举方法快了大约10毫秒. (2认同)

Cla*_*diu 7

这个问题的启发,我发现这非常优雅:

>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> next(i for i, t in enumerate(tuple_list) if t[1] == 7)
1
>>> next(i for i, t in enumerate(tuple_list) if t[0] == "kumquat")
2
Run Code Online (Sandbox Code Playgroud)


Ala*_*air 5

你可以用列表理解和索引()来做到这一点

tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
[x[0] for x in tuple_list].index("kumquat")
2
[x[1] for x in tuple_list].index(7)
1
Run Code Online (Sandbox Code Playgroud)