user2983638
user2983638

Reputation: 941

How to write a list comprehension without repeating the evaluation of a function?

My apologies for this trivial question, but I cannot find a solution. I need to create the following list:

for i in x:
    if(f(i) < g(i)):
         my_list.append(f(i)*g(i))

but I don't know how to do it with the list comprehension without repeating the calculation of the functions f() and g(). I want to avoid it because they are computationally expensive. So I don't want something like:

[f(i)*g(i) for i in x if f(i) < g(i)]

because f(i) and g(i) are calculated twice at every iteration. I was wondering if there is a way to "store" somewhere the numbers f(i) and g(i) and to recall them inside the list comprehension.

Upvotes: 1

Views: 351

Answers (4)

user58697
user58697

Reputation: 7923

Consider

[ fi * gi for fi, gi in zip(map(f, x), map(g, x)) if fi < gi ]

Upvotes: 1

vpekar
vpekar

Reputation: 3355

You can avoid using append, as follows:

def func(x):
    for i in x:
        a = f(i)
        b = g(i)
        if a < b:
            yield a*b

my_list = list(func(x))

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1124758

You can store the values of the calls in a for loop target, if you create an iterable (like a tuple or a list) with just one element in it; that one element would be a tuple with the (f(i), g(i)) result herer:

res = [fi * gi for i in x for fi, gi in [(f(i), g(i))] if fi < gi]

This is, however, not pretty and not very readable.

You'd be far better off using an actual for loop for this:

res = []
for i in x:
    fi, gi = f(i), g(i)
    if fi < gi:
        res.append(fi * gi)

Another option is to produce an intermediate generator expression that calculates f(i) and g(i), then uses the output in a list comprehension:

intermediate = ((f(i), g(i)) for i in x)
res = [fi * gi for fi, gi in intermediate if fi < gi]

Upvotes: 2

Marcus M&#252;ller
Marcus M&#252;ller

Reputation: 36482

um... very basic... what about variables to store the result of g(i) and f(i) ?

instead of

for i in x:
    if(f(i) < g(i)):
         my_list.append(f(i)*g(i))

do something like

for i in x:
    a = f(i)
    b = g(i)
    if a < b:
         my_list.append(a*b)

Upvotes: 1

Related Questions