Arrays/List, filters, Pytho, Ruby

LL.Snark ll.snark at gmail.com
Mon Feb 14 15:07:46 CET 2011


On 12/02/2011 04:49, Terry Reedy wrote:
> On 2/11/2011 4:24 PM, LL.Snark wrote:
>> 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)









More information about the Python-list mailing list