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