Find the index of an item in a list of lists

It would be perhaps more simple using 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.


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

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

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


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:

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)

Using enumerate() you could write a function like this one:

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