[[x,f(x)] for x in list that maximizes f(x)] <--newbie help

  • Thread starter Niels L Ellegaard
  • Start date
N

Niels L Ellegaard

I just started learning python and I have been wondering. Is there a
short pythonic way to find the element, x, of a list, mylist, that
maximizes an expression f(x).

In other words I am looking for a short version of the following:

pair=[mylist[0],f(mylist[0])]
for x in mylist[1:]:
if f(x) > pair[1]:
pair=[x,f(x)]
 
B

bearophileHUGS

If the elements of mylist can be compared (es. not complex values),
then this can be a solution for you:

from math import sin as f
mylist = [float(2*i)/10 for i in xrange(10)]
pairs = [(f(x), x) for x in mylist]
ymax = max(pairs)[1]
print pairs, "\n"
print ymax

You can also try this, for Py2.4:
print max((f(x), x) for x in mylist)[1]

Bye,
bearophile
 
B

bonono

Niels said:
I just started learning python and I have been wondering. Is there a
short pythonic way to find the element, x, of a list, mylist, that
maximizes an expression f(x).

In other words I am looking for a short version of the following:

pair=[mylist[0],f(mylist[0])]
for x in mylist[1:]:
if f(x) > pair[1]:
pair=[x,f(x)]

this is already very short, what else you want? May be this :

max(((f(x), x) for x in mylist))

That is first generate the (f(x),x) pairs then find the max one(first
compare f(x) then x)
 
D

Duncan Booth

wrote:
In other words I am looking for a short version of the following:

pair=[mylist[0],f(mylist[0])]
for x in mylist[1:]:
if f(x) > pair[1]:
pair=[x,f(x)]

this is already very short, what else you want? May be this :

max(((f(x), x) for x in mylist))

That is first generate the (f(x),x) pairs then find the max one(first
compare f(x) then x)

It might be better to do:

max((f(x),i,x) for i,x in enumerate(mylist))[2]

as that will handle the case where x is not comparable but f(x) is.

e.g.
mylist = (3j, 5j+2, 1j)
max((abs(x),i,x) for i,x in enumerate(mylist))[2]
(2+5j)
 
B

bonono

Duncan said:
wrote:
In other words I am looking for a short version of the following:

pair=[mylist[0],f(mylist[0])]
for x in mylist[1:]:
if f(x) > pair[1]:
pair=[x,f(x)]

this is already very short, what else you want? May be this :

max(((f(x), x) for x in mylist))

That is first generate the (f(x),x) pairs then find the max one(first
compare f(x) then x)

It might be better to do:

max((f(x),i,x) for i,x in enumerate(mylist))[2]

as that will handle the case where x is not comparable but f(x) is.

e.g.
mylist = (3j, 5j+2, 1j)
max((abs(x),i,x) for i,x in enumerate(mylist))[2]
(2+5j)
thanks. I don't know what max can or cannot compare.
 
A

Alex Martelli

thanks. I don't know what max can or cannot compare.

Just the same things that you can compare with, say, < .

I believe in 2.5 max and min will also accept a key= argument (like
sorted etc) to tweak what to compare, so max(thelist, key=f) should then
work (but in 2.4 you do need to more explicitly use some kind of
decorate-sort-undecorate idiom, as explained in previous posts).


Alex
 
B

bonono

Alex said:
Just the same things that you can compare with, say, < .

I believe in 2.5 max and min will also accept a key= argument (like
sorted etc) to tweak what to compare, so max(thelist, key=f) should then
work (but in 2.4 you do need to more explicitly use some kind of
decorate-sort-undecorate idiom, as explained in previous posts).
Thanks. In that case, would it be easier to understand(beside the
original iterative loop) if I use reduce and lambda ?

reduce(lambda (mv,mx), (v,x): mv > v and (mv,mx) or (v,x), ((f(x), x)
for x in mylist)))

As while DSU is a very smart way to guard the max compare thing, it is
still being introduced as a way that is not related to the original
problem, i.e. I just want to compare f(x)
 
B

Bengt Richter

I just started learning python and I have been wondering. Is there a
short pythonic way to find the element, x, of a list, mylist, that
maximizes an expression f(x).

In other words I am looking for a short version of the following:

pair=[mylist[0],f(mylist[0])]
for x in mylist[1:]:
if f(x) > pair[1]:
pair=[x,f(x)]

Reversing the order of the pair:
>>> mylist = range(10)
>>> def f(x): return 10-(x-5)**2 ...
>>> [f(x) for x in mylist]
[-15, -6, 1, 6, 9, 10, 9, 6, 1, -6]

Then one line should do it:
(10, 5)

Ok, be picky ;-)
[5, 10]

Regards,
Bengt Richter
 
D

Duncan Booth

Thanks. In that case, would it be easier to understand(beside the
original iterative loop) if I use reduce and lambda ?
You could try putting them side by side and seeing which is easiest for
someone to understand:

reduce(lambda (mv,mx), (v,x): mv > v and (mv,mx) or (v,x), ((f(x), x) for x
in mylist)))

max((f(x),i,x) for i,x in enumerate(mylist))[2]

max_x, max_f = mylist[0], f(mylist[0])
for x in mylist[1:]:
new_f = f(x)
if new_f > max_f:
max_x, max_f = x, new_f

IMO, the last is clearest (but needs a list rather than an iterator), the
middle is most concise and not too hard to understand and the first is a
complete mess. YMMV.
 
A

Alex Martelli

As while DSU is a very smart way to guard the max compare thing, it is
still being introduced as a way that is not related to the original
problem, i.e. I just want to compare f(x)

And that's why in 2.5 you'll just code max(mylist, key=f) to express
this intent exactly -- that's precisely what 'key=' means.


Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top