Home > Blockchain >  Avoiding re-computing the same expression in Python
Avoiding re-computing the same expression in Python

Time:12-08

In the following code, I use abs(v - i) three times on the same line. Is this expression computed three times when the code is run? Is there a way to avoid this without having to complicate the code?

x = sum(abs(v-i) if s == 1 else int((abs(v-i)*(abs(v-i) 1))/2) for v in list)

CodePudding user response:

My answer only shows that it's possible to do what you want with a one-liner, but I would still advise to use a longer approach with an explicit if/else caching the value, or using numpy arrays and masks.

You can use the walrus operator := to store the value as a variable. This line is equivalent to your original code and will only compute a = abs(v-i) once per loop instead of 1-2 times:

x = sum(a if s == 1 and ((a := abs(v-i)) is not None) else int(a*(a 1)/2) for v in list_)

The problem is that the walrus operator can only be used in a if check, so we need to add a check that's always true... It really doesn't help reading comprehension.

"Long" approach:

v = np.array(list_)
a = np.abs(v - i)
x = np.sum(a if s == 1 else np.int(a*(a 1)/2))```

CodePudding user response:

While https://stackoverflow.com/a/70268402/1126841 regarding the assignment operator is correct, this is a case where I really dislike the assignment expression, as you have to hunt for where a is actually defined. I would probably ditch sum and accumulate the value in a for loop instead.

x = 0
for v in list_:
    a = abs(v-i)
    if s == 1:
        x  = a
    else:
        x  = int(a*(a 1)/2)

However, since s never changes in the loop, I would refactor this into two separate loops chosen by the value of s, one of which can use sum without difficulty.

if s == 1:
    x = sum(abs(v-i) for v in list_)
else:
    x = 0
    for v in list_:
        a = abs(v-i)
        x  = int(a*(a 1)/2)

CodePudding user response:

Is this expression computed three times when the code is run?

No, once or twice for every list value.

Is there a way to avoid this without having to complicate the code?

Depends on what you consider complicating the code.

You could use the idiom that even got optimized in Python 3.9:

x = sum(a if s == 1 else int((a*(a 1))/2)
        for v in list
        for a in [abs(v-i)])

Or if your list values are ints, you could use math.comb:

x = sum(abs(v-i) if s == 1 else comb(abs(v-i) 1, 2) for v in list)

CodePudding user response:

Can't you just save abs(v-i) to a variable and then substitute in that variable?

I would create a variable called my_calc = abs(v-i) then use that name. This will clean up your code

  • Related