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"]]
whats the cleanest way of search the list, and returning the position of one of the items, e.g. "#660000"?
I have looked at the index method, but that doesn't seem to unpack the list inside the list.
postion=colours.index("#660000")
gives: ValueError: ['#660000'] is not in list, not [0][0] as I expect...
解决方案
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.