Velocity Reviews > Arrays/List, filters, Pytho, Ruby

# Arrays/List, filters, Pytho, Ruby

LL.Snark
Guest
Posts: n/a

 02-11-2011
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 is the index, in array t, of the first element x such that x<t[0].

If can write it in python several ways :
t=[6,7,8,6,7,9,8,4,3,6,7]
i=0
while t[i]>=t[0] : i+=1

.... not pythonic I think...

Or :
t=[6,7,8,6,7,9,8,4,3,6,7]
i=[j for j in range(len(t)) if t[j]<t[0]][0]

....too cryptic...

I'm using Python 3.

Thx

Chris Rebert
Guest
Posts: n/a

 02-11-2011
On Fri, Feb 11, 2011 at 1:24 PM, LL.Snark <(E-Mail Removed)> 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 is the index, in array t, of the first element x such that x<t[0].
>
> If can write it in python several ways :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=0
> while t[i]>=t[0] : i+=1
>
> ... not pythonic I think...
>
> Or :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=[j for j in range(len(t)) if t[j]<t[0]][0]
>
> ...too cryptic...
>
> I'm using Python 3.

My version:

t = [6,7,8,6,7,9,8,4,3,6,7]
i = -1
for index, item in enumerate(t):
if item < t[0]:
i = index
break

I'm a big fan of enumerate().
I'm sure an itertools solution is also possible.

Cheers,
Chris
--
http://blog.rebertia.com

Dan Stromberg
Guest
Posts: n/a

 02-11-2011
On Fri, Feb 11, 2011 at 1:43 PM, André Roberge <(E-Mail Removed)> wrote:
> On Friday, February 11, 2011 5:24:15 PM UTC-4, 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 is the index, in array t, of the first element x such that x<t[0].
>>
>> If can write it in python several ways :
>> t=[6,7,8,6,7,9,8,4,3,6,7]
>> i=0
>> while t[i]>=t[0] : i+=1
>>
>> ... not pythonic I think...
>>
>> Or :
>> t=[6,7,8,6,7,9,8,4,3,6,7]
>> i=[j for j in range(len(t)) if t[j]<t[0]][0]
>>
>> ...too cryptic...
>>

> You could go with something like (untested)
> t = [6,7,8,6,7,9,8,4,3,6,7]
> for i, j in enumerate(t):
> * *if j < t[0]:
> * * * *break
> else:
> * * * *i = 0
>
>
>
>
>
>> I'm using Python 3.
>>
>> Thx

>>> t = [6,7,8,6,7,9,8,4,3,6,7]
>>> generator = (element for element in t[1:] if element >= t[0])
>>> print(next(generator))

Ian
Guest
Posts: n/a

 02-11-2011
On Feb 11, 2:24*pm, "LL.Snark" <(E-Mail Removed)> 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}

More Javalicious than Pythonic, but this works:

class ComparisonPredicate:

def __init__(self, func):
self.func = func

def __eq__(self, other):
return self.func(other)

t = [6, 7, 8, 6, 7, 9, 8, 4, 3, 6, 7]
print(t.index(ComparisonPredicate(lambda x: x < t[0])))

Dan Stromberg
Guest
Posts: n/a

 02-11-2011
On Fri, Feb 11, 2011 at 1:51 PM, Dan Stromberg <(E-Mail Removed)> wrote:
> On Fri, Feb 11, 2011 at 1:43 PM, André Roberge <(E-Mail Removed)> wrote:
>> On Friday, February 11, 2011 5:24:15 PM UTC-4, 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 is the index, in array t, of the first element x such that x<t[0].
>>>
>>> If can write it in python several ways :
>>> t=[6,7,8,6,7,9,8,4,3,6,7]
>>> i=0
>>> while t[i]>=t[0] : i+=1
>>>
>>> ... not pythonic I think...
>>>
>>> Or :
>>> t=[6,7,8,6,7,9,8,4,3,6,7]
>>> i=[j for j in range(len(t)) if t[j]<t[0]][0]
>>>
>>> ...too cryptic...
>>>

>> You could go with something like (untested)
>> t = [6,7,8,6,7,9,8,4,3,6,7]
>> for i, j in enumerate(t):
>> * *if j < t[0]:
>> * * * *break
>> else:
>> * * * *i = 0
>>
>>
>>
>>
>>
>>> I'm using Python 3.
>>>
>>> Thx

>
>>>> t = [6,7,8,6,7,9,8,4,3,6,7]
>>>> generator = (element for element in t[1:] if element >= t[0])
>>>> print(next(generator))

>

Oops; a correction. Fast and concise - and if you decide you need the
2nd or 10th, they'll be on their way as soon as you request them (lazy
evaluation):

>>> generator = (ind+1 for ind, element in enumerate(t[1:]) if element >= t[0])
>>> print(next(generator))

Paul Rubin
Guest
Posts: n/a

 02-11-2011
"LL.Snark" <(E-Mail Removed)> writes:

> 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}

from itertools import dropwhile

t=[6,7,8,6,7,9,8,4,3,6,7]
i = dropwhile(lambda k: t[k]>=t[0], t).next()

Note the above can throw an exception if no suitable element is found.

t=[6,7,8,6,7,9,8,4,3,6,7]
i=[j for j in range(len(t)) if t[j]<t[0]][0]

That traverses the whole list even if the desired element is near the
beginning of the list. I don't kow if the Ruby version does the same.

Jon Clements
Guest
Posts: n/a

 02-11-2011
On Feb 11, 9:24*pm, "LL.Snark" <(E-Mail Removed)> 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 is the index, in array t, of the first element x such that x<t[0].
>
> If can write it in python several ways :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=0
> while t[i]>=t[0] : i+=1
>
> ... not pythonic I think...
>
> Or :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=[j for j in range(len(t)) if t[j]<t[0]][0]
>
> ...too cryptic...
>
> I'm using Python 3.
>
> Thx

My take (but using Python 2.x):

import operator as op
from functools import partial
from itertools import islice

t = [6,7,8,6,7,9,8,4,3,6,7]

def first_conditional(seq, first=op.itemgetter(0), pred=op.gt):
f = first(seq)
cmpfunc = partial(pred, f)
for idx, val in enumerate(islice(seq, 1, None)):
if cmpfunc(val): return idx + 1
return -1 # or raise an exception?

Off top of head, so needs work, but is fairly generic.

Jon.

LL.Snark
Guest
Posts: n/a

 02-12-2011
On 11/02/2011 22:24, 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 is the index, in array t, of the first element x such that x<t[0].
>
> If can write it in python several ways :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=0
> while t[i]>=t[0] : i+=1
>
> ... not pythonic I think...
>
> Or :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=[j for j in range(len(t)) if t[j]<t[0]][0]
>
> ...too cryptic...
>
> I'm using Python 3.

================================================== ===
t = [6,7,8,6,7,9,8,4,3,6,7]
i = -1
for index, item in enumerate(t):
if item < t[0]:
i = index
break

is OK for me, while a bit too long
================================================== ====
from itertools import dropwhile
t=[6,7,8,6,7,9,8,4,3,6,7]
i = dropwhile(lambda k: t[k]>=t[0], t).__next__()
(I added the __ around next. Am i true ?)

This does not work for me.

i is effectively 7, but 7 is the second item of the array.
If you try :
t=[6,8,8,6,7,9,8,4,3,6,7]
i = dropwhile(lambda k: t[k]>=t[0], t).__next__()
You will get 8.

I guess this is because k is a value of the array, not an index.
In the first example, we compare t[6], then t[7], then t[8], t[6], t[7]
etc... to t[0].
(It happens that the first item of the list is dropped... then the first
element of the resulting list is 7... the answer... but it was just luck)

================================================== ===
The javalicious one :

class ComparisonPredicate:
def __init__(self, func):
self.func = func
def __eq__(self, other):
return self.func(other)

t = [6, 7, 8, 6, 7, 9, 8, 4, 3, 6, 7]
print(t.index(ComparisonPredicate(lambda x: x < t[0])))

It took me some time to understand
It's a shame there is no built-in object like ComparisonPredicate,
because the line t.index(ComparisonPredicate(lambda x: x < t[0])) looks
good to me.

================================================== =
Finally, the other enumerate solution may be written like this :
t = [6,7,8,6,7,9,8,4,3,6,7]
for i, j in enumerate(t):
if j < t[0]: break
else : i=-1
Quite short.

=================================================
Finally, with your solutions, I build another one. Here it is :
t=[6,7,8,6,7,9,8,4,3,6,7]
i,j=filter(lambda x: x[1]<t[0],enumerate(t)).__next__()

Or :
from itertools import dropwhile
t=[6,7,8,6,7,9,8,4,3,6,7]
i,j=dropwhile(lambda x: x[1]>=t[0],enumerate(t)).__next__()

Or else :
t=[6,7,8,6,7,9,8,4,3,6,7]
t.index(filter(lambda x: x<t[0],t).__next__())

The last one behaves like the Ruby one, if a value is found. If no walue
is found, the Python code raises a StopException. With the Ruby code, i
is nil.

Is there another way to access the first item of an iterator ?
( __next__() is ugly )

================================================== ====
Paul, the Ruby version stops when it finds the first matching element
t=[6,7,8,6,7,9,8,4,3,6,7]
i=t.index {|x| x<t.first}

(I figured this out by making a 1 000 000 elements array. It was faster
with a matching value at the beginning of the array)

Terry Reedy
Guest
Posts: n/a

 02-12-2011
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 is the index, in array t, of the first element x such that x<t[0].

What does Ruby do if there is no such element?
For Python, the answer should be either None or ValueError.

>
> If can write it in python several ways :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=0
> while t[i]>=t[0] : i+=1

This will raise IndexError when i gets too big.

> ... not pythonic I think...
>
> Or :
> t=[6,7,8,6,7,9,8,4,3,6,7]
> i=[j for j in range(len(t)) if t[j]<t[0]][0]

This will raise IndexError if the list is empty.

--
Terry Jan Reedy

Bruno Piguet
Guest
Posts: n/a

 02-12-2011
On 11 fév, 22:24, "LL.Snark" <(E-Mail Removed)> 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}

I'm thinking of two methods, depending on the length of the list, and
the fact that you wish (or not) to scan the whole list.

The first one, quite simple, but scanning the whole list :
t=[6,7,8,6,7,9,8,4,3,6,7]
[x<t[0] for x in t].index(True)

The alternative method, which will stop at the first element matching
the condition, but which might be less readable :
next(i for i, x in enumerate(t) if x<t[0])

If there is a risk that no element match the condition, and you don't
want an StopIteration exception, use the second optionnal argument of
next :
or
next((i for i, x in enumerate(t) if x>1000), None)
Note that if you use the second optionnal argument of next, you'll
need an additional pair of parentheses around
the generator expression which is the first argument of next.

Bruno.