[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Re: Index of maximum element in list

Hexamorph

1/25/2008 9:48:00 PM

Henry Baxter wrote:
> Oops, gmail has keyboard shortcuts apparently, to continue:
>
> def maxi(l):
> m = max(l)
> for i, v in enumerate(l):
> if m == v:
> return i
>

What's about l.index(max(l)) ?
15 Answers

Raymond Hettinger

1/26/2008 4:17:00 AM

0

On Jan 25, 1:47 pm, Hexamorph <hexamo...@gmx.net> wrote:
> Henry Baxter wrote:
> > Oops, gmail has keyboard shortcuts apparently, to continue:
>
> > def maxi(l):
> >     m = max(l)
> >     for i, v in enumerate(l):
> >         if m == v:
> >             return i
>
> What's about l.index(max(l)) ?

from itertools import izip, count
answer = max(izip(l, count()))[1]


Raymond

Scott David Daniels

1/26/2008 5:53:00 AM

0

Hexamorph wrote:
> ...
> What's about l.index(max(l)) ?
What about
max((x,i) for i,x in enumerate(lst))[1]

Bearophile

1/26/2008 9:52:00 AM

0

> Henry Baxter wrote:
> > def maxi(l):
> > m = max(l)
> > for i, v in enumerate(l):
> > if m == v:
> > return i
>
> What's about l.index(max(l)) ?

The version I use:

def posmax(seq, key=None):
"""Return the position of the first maximum item of a sequence.
It accepts the usual key parameter too."""
if key:
return max(enumerate(seq), key=lambda k: key(k[1]))[0]
else:
return max(enumerate(seq), key=itemgetter(1))[0]

Bye,
bearophile

Paul Rubin

1/26/2008 10:25:00 AM

0

bearophileHUGS@lycos.com writes:
> def posmax(seq, key=None):
> """Return the position of the first maximum item of a sequence.
> It accepts the usual key parameter too."""
> if key:
> return max(enumerate(seq), key=lambda k: key(k[1]))[0]
> else:
> return max(enumerate(seq), key=itemgetter(1))[0]

def posmax(seq, key=lambda x:x):
return max(enumerate(seq), key=lambda k: key(k[1]))[0]

Bearophile

1/26/2008 4:28:00 PM

0

Paul Rubin:
> def posmax(seq, key=lambda x:x):
> return max(enumerate(seq), key=lambda k: key(k[1]))[0]

Is the Python max able to tell that's the identity function? I don't
think so, so your version may be slower and more memory hungry in the
common situation where you don't have a key function. So I think my
version is better :-)

Bye,
bearophile

Paul Rubin

1/26/2008 8:40:00 PM

0

bearophileHUGS@lycos.com writes:
> > def posmax(seq, key=lambda x:x):
> > return max(enumerate(seq), key=lambda k: key(k[1]))[0]
>
> Is the Python max able to tell that's the identity function? I don't
> think so, so your version may be slower and more memory hungry in the
> common situation where you don't have a key function. So I think my
> version is better :-)

I don't think there will be a noticable memory increase. It's not a
DSU situation like in sorting, it's just a small constant parameter.
Yes there might be a small speed hit. The compiler in principle could
convert the (lambda k: lambda x: k[1]) to something like
operator.itemgetter(1), but I doubt that it actually does so.

Steven D'Aprano

1/26/2008 10:08:00 PM

0

On Sat, 26 Jan 2008 12:40:26 -0800, Paul Rubin wrote:

> bearophileHUGS@lycos.com writes:
>> > def posmax(seq, key=lambda x:x):
>> > return max(enumerate(seq), key=lambda k: key(k[1]))[0]
>>
>> Is the Python max able to tell that's the identity function? I don't
>> think so, so your version may be slower and more memory hungry in the
>> common situation where you don't have a key function. So I think my
>> version is better :-)
>
> I don't think there will be a noticable memory increase. It's not a DSU
> situation like in sorting, it's just a small constant parameter. Yes
> there might be a small speed hit. The compiler in principle could
> convert the (lambda k: lambda x: k[1]) to something like
> operator.itemgetter(1), but I doubt that it actually does so.

Actually there is a big speed hit. Until such time that Python has a fast
identity function, and lambda x:x isn't it, your version is about three
times slower than Bearophile's.

Much to my surprise, the fastest solution I've tried appears to be a pure
Python version not even using max() at all.

Here are the three versions:

def posmax1(seq, key=None): # bearophile's version
"""Return the position of the first maximum item of a sequence.
It accepts the usual key parameter too."""
if key:
return max(enumerate(seq), key=lambda k: key(k[1]))[0]
else:
return max(enumerate(seq), key=itemgetter(1))[0]


def posmax2(seq, key=lambda x:x): # Paul Rubin's version
return max(enumerate(seq), key=lambda k: key(k[1]))[0]


def posmax3(seq, key=None): # Pure Python version
if key is None:
m = seq[0]
index = 0
for i, x in enumerate(seq):
if x > m:
m = x
index = i
return index
else:
return NotImplemented



And my timing results:

>>> alist = [3]*1000 + [5] + [3]*1000
>>> assert alist.index(5) == 1000
>>> assert posmax1(alist) == posmax2(alist) == posmax3(alist) == 1000
>>>
>>> min(timeit.Timer('posmax1(alist)',
.... 'from __main__ import posmax1, alist').repeat(number=1000))/1000
0.00074387979507446289
>>> min(timeit.Timer('posmax2(alist)',
.... 'from __main__ import posmax2, alist').repeat(number=1000))/1000
0.0022983889579772949
>>> min(timeit.Timer('posmax3(alist)',
.... 'from __main__ import posmax3, alist').repeat(number=1000))/1000
0.00063846302032470701



--
Steven

Bearophile

1/26/2008 10:13:00 PM

0

Steven D'Aprano:
> Much to my surprise, the fastest solution I've tried appears to be a pure
> Python version not even using max() at all.

That version is easy to translate to other languages and you can
probably find that Psyco makes it much faster still.

Bye,
bearophile

Paul Rubin

1/26/2008 10:18:00 PM

0

Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> Actually there is a big speed hit. Until such time that Python has a fast
> identity function, and lambda x:x isn't it, your version is about three
> times slower than Bearophile's.

Interesting. Fixing that speed hit probably needs compiler attention.

> Much to my surprise, the fastest solution I've tried appears to be a pure
> Python version not even using max() at all.

Could you try the l.index version? That avoids creating all those
intermediate tuples.

Bearophile

1/27/2008 10:49:00 AM

0

bearophile:
> That version is easy to translate to other languages and you can
> probably find that Psyco makes it much faster still.

That operation is quite common, so it deserves a bit more work:
http://aspn.activestate.com/ASPN/Cookbook/Python/Rec...

(I can show you the D/C code if you want it. The C code is just for
testing, while the D code is usable).

The final sum: the Psyco version is almost 40 times faster than the
Python version, and just 2.8 times slower than the D version, and 3.4
times slower than a C version (that doesn't use too many pointer
tricks). I think this is good enough.

Bye,
bearophile