简体   繁体   English

在列表列表中查找项目的索引

[英]Find the index of an item in a list of lists

I have a list of lists:我有一个列表列表:

colours = [["#660000","#863030","#ba4a4a","#de7e7e","#ffaaaa"],["#a34b00","#d46200","#ff7a04","#ff9b42","#fec28d"],["#dfd248","#fff224","#eefd5d","#f5ff92","#f9ffbf"],["#006600","#308630","#4aba4a","#7ede7e","#aaffaa"]]

What's the cleanest way of searching the list and returning the position of one of the items, eg "#660000" ?搜索列表并返回其中一项的位置的最简洁方法是什么,例如"#660000"

I have looked at the index method, but that doesn't seem to unpack the list inside the list.我已经查看了index方法,但这似乎并没有将列表中的列表解包。

postion = colours.index("#660000")

gives: ValueError: ['#660000'] is not in list , not [0][0] as I expect...给出: ValueError: ['#660000'] is not in list , not [0][0]正如我所期望的......

I'd do something like this:我会做这样的事情:

[(i, colour.index(c))
 for i, colour in enumerate(colours)
 if c in colour]

This will return a list of tuples where the first index is the position in the first list and second index the position in the second list (note: c is the colour you're looking for, that is, "#660000" ).这将返回一个元组列表,其中第一个索引是第一个列表中的位置,第二个索引是第二个列表中的位置(注意: c是您要查找的颜色,即"#660000" )。

For the example in the question, the returned value is:对于问题中的示例,返回值是:

[(0, 0)]

If you just need to find the first position in which the colour is found in a lazy way you can use this:如果您只需要以懒惰的方式找到找到颜色的第一个位置,您可以使用:

next(((i, colour.index(c))
      for i, colour in enumerate(colours)
      if c in colour),
     None)

This will return the tuple for the first element found or None if no element is found (you can also remove the None argument above in it will raise a StopIteration exception if no element is found).这将返回找到的第一个元素的元组,如果没有找到元素,则返回None (您也可以删除上面的None参数,如果没有找到元素,它将引发StopIteration异常)。

Edit: As @RikPoggi correctly points out, if the number of matches is high, this will introduce some overhead because colour is iterated twice to find c .编辑:正如@RikPoggi 正确指出的那样,如果匹配数很高,这将引入一些开销,因为colour被迭代两次以找到c I assumed this to be reasonable for a low number of matches and to have an answer into a single expression.我认为这对于少量匹配是合理的,并且可以将答案转换为单个表达式。 However, to avoid this, you can also define a method using the same idea as follows:但是,为了避免这种情况,您还可以使用相同的想法定义一个方法,如下所示:

def find(c):
    for i, colour in enumerate(colours):
        try:
            j = colour.index(c)
        except ValueError:
            continue
        yield i, j

matches = [match for match in find('#660000')]

Note that since find is a generator you can actually use it as in the example above with next to stop at the first match and skip looking further.请注意,由于find是一个生成器,您实际上可以像上面的示例一样使用它, next在第一场比赛时停止并跳过进一步查找。

Using enumerate() you could write a function like this one:使用enumerate()你可以写一个这样的函数:

def find(target):
    for i,lst in enumerate(colours):
        for j,color in enumerate(lst):
            if color == "#660000":
                return (i, j)
    return (None, None)

It would be perhaps more simple using numpy :使用numpy可能更简单:

>>> import numpy
>>> ar = numpy.array(colours)
>>> numpy.where(ar=="#fff224")
(array([2]), array([1]))

As you see you'll get a tuple with all the row and column indexes.如您所见,您将获得一个包含所有行和列索引的元组。

If you want to evade from iterating the target sublist twice, it seems that the best (and the most Pythonic) way to go is a loop:如果你想避免迭代目标子列表两次,似乎最好的(也是最 Python 化的)方法是循环:

def find_in_sublists(lst, value):
    for sub_i, sublist in enumerate(lst):
        try:
            return (sub_i, sublist.index(value))
        except ValueError:
            pass

    raise ValueError('%s is not in lists' % value)

In Python 3, I used this pattern:在 Python 3 中,我使用了这种模式:

CATEGORIES = [   
    [1, 'New', 'Sub-Issue', '', 1],
    [2, 'Replace', 'Sub-Issue', '', 5],
    [3, 'Move', 'Sub-Issue', '', 7],
]

# return single item by indexing the sub list
next(c for c in CATEGORIES if c[0] == 2)

您可以做的另一件事是选择您想要的列表部分,然后使用索引找到它

list_name[0].index("I want coffee")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM