tags:

views:

188

answers:

7

What would be the most pythonesque way to find the first index in a list that is greater than x?

For example, with

list = [0.5, 0.3, 0.9, 0.8]

The function

f(list, 0.7)

would return

2.
A: 
>>> f=lambda seq, m: [ii for ii in xrange(0, len(seq)) if seq[ii] > m][0]
>>> f([.5, .3, .9, .8], 0.7)
2
flybywire
That looks pretty slick. But theoretically it will traverse the whole list and then return the first result (greater than x), right? Is there any way to make one that stops straight after finding the first result?
c00kiemonster
yes, it traverses all the list
flybywire
what's wrong with traversing whole list? if the first value greater than 0.7 is near the end of the list, it doesn't make a difference.
ghostdog74
True. But in this particular case the lists I intend to use the function on are pretty long, so I'd prefer it to quit traversing as soon as a match is found...
c00kiemonster
whether its long or not, if the first value is the last second item of the list, you will still have to traverse the whole list to get there!
ghostdog74
@ghostdog74: Yes, but this is not a reason to want all cases to be worst cases.
UncleBens
+9  A: 
next(x[0] for x in enumerate(L) if x[1] > 0.7)
Ignacio Vazquez-Abrams
+1: Although I would prefer to avoid the magic numbers: next(idx for idx, value in enumerate(L) if value > 0.7)
truppo
+1 for simplicity and `next()`, but maybe this for readability: `next(i for i,v in enumerate(L) if v > 0.7)`
Will Hardy
While this is nice looking, the case where there's no result will raise a confusing StopIteration.
Virgil Dupras
Correct me if I'm wrong here, but the next() method will basically just keep on asking for the next item until it has found a match, right? So all I got to do is to catch a possible StopIteration as Virgil points out.
c00kiemonster
@c00kiemonster no, next() just gets the first item of the iterator. But the iterator is filtered, so the first item is the right item.
Virgil Dupras
why doesn't my python have next? is there something I need to import?
flybywire
@flybywire: `next()` is in 2.6+. Call the `next()` method of the genex in earlier versions.
Ignacio Vazquez-Abrams
To avoid the StopIteration problem and return -1 instead, you can use ([i for i,v in enumerate(L) if v > 0.7] + [-1])[0]
Wim
@Wim: But then you regress back to evaluating the entire sequence. Use `itertools.chain()` instead of adding lists like this.
Ignacio Vazquez-Abrams
Oh right, I didn't get the quick exit part yet... `next(itertools.chain(iter(i for i,v in enumerate(L) if v > 0.7), [-1]))` then?
Wim
+3  A: 
for index, elem in enumerate(elements):
    if elem > reference:
        return index
raise ValueError("Nothing Found")
Virgil Dupras
+4  A: 
>>> alist= [0.5, 0.3, 0.9, 0.8]
>>> [ n for n,i in enumerate(alist) if i>0.7 ][0]
2
ghostdog74
beat me to it:)
Charles Beattie
it will fail if 'x' is greater than any other value in the list
mshsayem
@mshsayem: Problem is ill-defined for this case. Failure may be the right thing to do.
S.Lott
A: 

Another one:

map(lambda x: x>.7, seq).index(True)
flybywire
+4  A: 
filter(lambda x: x>.7, seq)[0]
flybywire
-1: While technically correct, dont use filter where a list comprehension is both more readable and more performant
truppo
A: 

if list is sorted then bisect_left(alist, value) is faster for a large list than next(i for i, x in enumerate(alist) if x >= value).

J.F. Sebastian