Index of item in list when only part of the item is known
This is a follow-up on a previous question of mine regarding searching in lists of lists
I have a list with pairs of values as lists in it.
[['a',5], ['b',3], ['c',2] ]
I know the first element of each pair but I don't know the second (it's the result of a calculation and stored in the list with the first element. I sorted the list in descending order of the calculated item.
I want to know in which position each of the items is, which would normally be:
list.index('a')
if I didn't have the numbers there. Is there a way to get the index number without knowing the entirety of the element?
Something like:
开发者_Go百科list.index(['a',?])
where ?
is a wildcard?
Or should I just create a new list from the ordered one with just the first item in order to get it's index?
[x[0] for x in list].index('a')
But if you are running this code several times, you might want to save the list of x[0]'s.
There's a similar solution to that of Ofris
D = dict([ [x[1][0], x[0] ] for x in list(enumerate(L)) ])
D['a']
#returns 0
But another nice feature is that if you tweak this a little you can pull out your original values
D = dict([ [x[1][0], (x[0], x[1][1] ) ] for x in list(enumerate(L)) ])
D['a'][0]
#returns 0
D['a'][1]
#returns 5
You already have the original list from which you know the first elements. List call it orig_list. Get the element's index from the original list and use that index in the new list to retrieve.
>>> orig_list = ['a','b','c']
>>> calc_list = [['a',5], ['b',3], ['c',2] ]
>>> calc_list[orig_list.index('a')]
['a',5]
A simple, flexible one line version:
[i for (i, item) in enumerate([('a', 1), ('b', 3), ('a', 5)]) if item[0] == 'a']
# returns [0, 2]
[i for (i, item) in enumerate([('a', 1), ('b', 3), ('a', 5)]) if item[0] == 'a'][0]
# returns 0
You could wrap it in a function, replace item[0] == 'a'
with a call to an arbitrary predicate (like in my original answer; that's where it's flexible) etc. The second version above will throw an exception if no item is found, so wrap it in try/except; the first one will return an empty list.
If you prefer a separate function for the job, check out the one below... It has the benefit of only consuming as much of your iterable as needed to find an appropriate item.
Original answer:
This will allow you to find the index of the first item possessing any property you can think of, though you'll need to express it as a function (a lambda x: x[0] == 'a'
suffices in your example case):
def index_by(pred, iterable):
i = 0
found = False
for item in iterable:
if pred(item):
found = True
break
i += 1
return i if found else None
Call like so:
index_by(lambda x: x[0] == 'a', [('b', 1), ('a', 5)]) # returns 1
to obtain the zero-based index of the first item in the iterable which satisfies the given predicate. (In other words, the first item in the iterable passed in as the second argument for which the function passed in as the first argument returns a true value.)
If the iterable does not contain an element satisfying the predicate, None
is returned.
The code below will get the indexes of all items in the list that match the pattern ['a', ?]
:
>>> l = [['a',5], ['b',3], ['c',2], ['a',8]]
>>> indexes = [l.index(x) for x in l if x[0] == 'a']
>>> print indexes
[0, 3]
精彩评论