Python - find an 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 is the cleanest way to search the list and return the position of one of the elements, for example. "#660000" ?

I looked at the index method, but it doesn't seem to decompress the list inside the list.

 postion=colours.index("#660000") 

gives: ValueError: ['#660000'] is not in list , not [0][0] , as I expect ...

+7
source share
6 answers

I would 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 the second is the position in the second list (note: c is the color you are looking for, ie "#660000" ).

For example, in the question, the return value is:

 [(0, 0)] 

If you just need to find the first position in which the color 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 a tuple for the first element found, or None if no element is found (you can also remove the None argument above, it will raise a StopIteration exception if the element is not found).

Edit: as @RikPoggi correctly points out, if the number of matches is large, this will lead to some overhead because the colour repeated twice to find c . I suggested that this is reasonable for a small number of matches and for an answer in a single expression. However, to avoid this, you can also define a method using the same idea as the following:

 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 above example, with next to stop at the first match and skip further.

+11
source

Using enumerate() , you can write a function like this:

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

If you want to avoid repeating the target subnet twice, it seems that the best (and most Pythonic) way 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) 
+4
source

It might be easier to use numpy :

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

As you can see, you get a tuple with all the row and column indices.

+3
source

In Python 3, I used this template:

 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) 
+1
source

another thing you can do is select the section of the list you need and then use the index to find it

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

All Articles