简体   繁体   中英

How do I print the variable values that result in the maximum of a function?

I want to compute the maximum value of a function in python, then print the maximum value, as well as values of the variables at that maximum.

I think I have gotten pretty far. In my example below, the function is just the values from x multiplied by the values from y multiplied by the values from z (in theory this function could be anything). The maximum of which would be 3 * 6 * 9 = 162 .

My problem is: if these lists are hundreds of numbers long, I don't really want to print the entire list of inputs, which could be a massive list hundreds of thousands of entries long.

I am only interested in the final set of values (so 3 6 9 here), but I just can't seem to work out how to print only this set.

Any help would be greatly appreciated.

Thanks!

p=[1,2,3]
q=[6,5,4]
r=[7,8,9]

def f(x,y,z):
    maximum=0
    for a in x:
        for b in y:
            for c in z:
                if a*b*c > maximum:
                    maximum = a*b*c
                    print (a,b,c)
    print (maximum)  

f(p,q,r)

Result:

1 6 7
1 6 8
1 6 9
2 6 7
2 6 8
2 6 9
3 6 7
3 6 8
3 6 9
162

Turns out writing your question out is a good way of solving it. Thanks anyway!

def f(x,y,z):
    maximum=0
    for a in x:
        for b in y:
            for c in z:
                if a*b*c > maximum:
                    j=(a,b,c)
                    maximum = a*b*c
    print (maximum)
    print (j)

The easiest way to do it would be to keep track of the values in the same way that you keep track of the current maximum:

def f(x,y,z):
    maximum = 0
    for a in x:
        for b in y:
            for c in z:
                if a*b*c > maximum:
                    maximum = a*b*c
                    
    print(maximum)

You can make your code more robust by using a technique different than setting maximum = 0 in the beginning. For example, what if your list only has negative numbers? The result will be wrong. You can use what is called a sentinel value, like None , to indicate the first iteration. A sentinel is a marker that indicates that an "invalid" value. That will ensure that the correct maximum is always found:

def f(x,y,z):
    maximum = 
    for a in x:
        for b in y:
            for c in z:
                if  or a*b*c > maximum:
                    maximum = a*b*c
                    
    print ()
    print (maximum)

You can improve the design of your code by returning the numbers you are interested in, instead of just printing them. That will allow you to manipulate them in any way you want, including printing them, afterwards. Python allows multiple return values using tuples, so you can do something like this:

def f(x,y,z):
    maximum = None
    for a in x:
        for b in y:
            for c in z:
                if maximum is None or a*b*c > maximum:
                    maximum = a*b*c
                    abc_max = (a, b, c)
    

An optimization you may want to consider is not evaluating your "function" more than once. This is especially important for more complex cases and functions that don't return the same value twice. You can replace the beginning of the if block with something like

...
current_value = a * b * c
if current_value > maximum:
    maximum = current_value
    ...

If you are really interested in making this work on arbitrary functions, you can use Python to do that. Functions are objects, and can be passed around just like lists, numbers and strings:

def f(, x, y, z):
    maximum = None
    for a in x:
        for b in y:
            for c in z:
                current = 
                if maximum is None or current > maximum:
                    maximum = current
                    abc_max = (a, b, c)
    return maximum, abc_max

max, pqr = f( p, q, r)

If you are interested in further generalizations, you can take a look at itertools , which has the function product for running a "flattened" version of your nested for loop. This will allow you to accept any number of input iterables, not just three. Python allows an arbitrary number of positional arguments using a * in the argument list. The argument with the * in its name will be a tuple of all the remaining positional arguments. It can be used in a lambda as well:

from functools import reduce
from itertools import product
from operator import mul

def f(fn, *iterables):
    max_values = max(product(*iterables), key=lambda x: fn(*x))
    return fn(*max_values), max_values

max, pqr = f(lambda *args: reduce(mul, args), p, q, r)

You could consider adding a comparator to do something other than computing the maximum. However, that would actually be overkill, since you can convert any other operation to a maximum computation using a properly implemented fn . That is the same logic to implementing Pythons sort functions in terms of a key instead of a comparator. In the example above, you could find the minimum value by flipping the sign of the key: lambda *args: -reduce(mul, args) . You could find the combination whose product is closest to it's sum with something like lambda *args: -abs(sum(args) - reduce(mul, args)) . The possibilities are vast.

Here is a link to an IDEOne example demonstrating the last version shown above: https://ideone.com/QNj55T . IDEOne is a handy tool for showing off or testing small snippets. I have no affiliation with it but I use it quite often.

Here is a solution that is a bit more streamlined and pythonic since you are wanting this to be a learning example. I also commented heavily so you can follow-along:

# importing this is necessary in python3 as `reduce` was removed in python3
import functools

p = [1,2,3]
q = [6,5,4]
r = [7,8,9]

def f (x,y,z):

    # 1. Combine the list arguments together into 1 list "[x,y,z]"
    # 2. Iterate over each list in the group of lists "for li in [x,y,z]"
    # 3. Get the max number within each list "max(li)"
    # 4. Assign the resulting list to the maxv variable "maxv = ..." yielding [3,6,9]
    maxv = [max(li) for li in [x,y,z]]

    # Print the 3 largest integers used to multiply next
    print( maxv )

    # Use reduce to multiply each list element by themselves
    product = functools.reduce(lambda x,y: x*y, maxv)

    # Print the output = 162 in this case
    print( product )

f(p,q,r)    

Update

Incase you don't know how many lists of integers are going to be passed into the function (perhaps more than 3) you could iterate over the entire argument handler and make that your list instead of coding [x,y,z] , like so:

p = [1,2,3]
q = [6,5,4]
r = [7,8,9]
s = [8,9,10]
t = [9,10,11]

def d (*args):
    maxv = [max(li) for li in [x for x in args]]
    print( maxv )
    product = functools.reduce(lambda x,y: x*y, maxv)
    print( product )

d(p,q,r)   # yields 162
d(p,q,r,s) # yields 1620
d(p,q,r,s,t) # yeilds 17820

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM