Hi,
I'm looking for a pythonic way to translate this short Ruby code :
t=[6,7,8,6,7,9,8,4,3,6,7]
i=t.index {|x| x<t.first}
If you don't know Ruby, the second line means :
What does Ruby do if there is no such element?
For Python, the answer should be either None or ValueError.
Ruby code :
# What is the index, in array t,
# of the first element x such that x<t[0].
t=[6,7,8,6,7,9,8,9,4,3,6,7]
i=t.index {|x| x<t.first}
Stops when the first value is found.
If no value is found, then i is nil (None equivalent)
(The answer if index 8, value 4)
Here is the last summary (Python 3) :
=====================================================
t=[6,7,8,6,7,9,8,9,4,3,6,7]
and then... :
=======================================================
for i, j in enumerate(t):
if j < t[0]: break
else : i=-1
# Now i==8 and j==4
# i==-1 if no value is found
======================================================
class ComparisonPredicate:
def __init__(self, func):
self.func = func
def __eq__(self, other):
return self.func(other)
t.index(ComparisonPredicate(lambda x: x < t[0]))
=> 8
# Raises an exception if no value found
======================================================
The following solutions raise a StopIteration exception if no value is
found. See below how to use the second argument of next
next(filter(lambda x: x[1]<t[0],enumerate(t)))
=> (8,4)
from itertools import dropwhile
next(dropwhile(lambda x: x[1]>=t[0],enumerate(t)))
=> (8,4)
Or if you don't like enumerate :
next(filter(lambda x: x<t[0],t))
=> 4
t.index(next(filter(lambda x: x<t[0],t))
=> 8
next(filter(t[0].__gt__, t))
=> 4
================================================================
Generators and enumerate :
next(i for i,v in enumerate(t) if v<t[0])
=> 8
If no values exists, this raises an exception. Second argument of next
can help you :
next((i for i,v in enumerate(t) if v<t[0]),None)
=> 8 # returns None if no value found
===========================================================
If you use lists instead of generators, it works, but you have to go
across the whole array :
[x<t[0] for x in t].index(True)
=> 8
[i for i,v in enumerate(t) if v < t[0]]
=> [ 8, 9 ] (indices of all array values less than t[0]
If you are only interested in the first value :
[i for i,v in enumerate(t) if v < t[0]][0]
=> 8 (but raises an exception if the list if no value is found)
[i for i,v in enumerate(t) if v < t[0]][0:1]
=> [8] (return an empty list if no value is found)
Keep in mind that, even if you just select the first value [0] or [0:1],
you go across the whole array t
=================================================
I found it very interesting to read all these short lines of code.
Thanks to : Chris, Ian, Paul, Jon, Therry, Bruno, Arnaud and people that
have no name (like me...)
next(((i,v) for i,v in enumerate(t) if v<t[0]),None)