0

I have working code, but am wondering if there is a numpy implementation for it. This more for satisfying my curiosity and about optimising and making code prettier; I don't have an acute problem. Still, I guess this situation is common enough to be interesting to others than just myself.

So, the situation: I'm calculating a value many times in a loop, and would like to only save the minimum and maximum value.

Initially, I used

import numpy as np
vals = []
for obj in objects:
    #...do stuff...
    vals.append(obj.calc_value())
    #...do more stuff
minmax = [np.min(vals), np.max(vals)]

which works and is nice and short. However, because I'm storing all values, yet only need the min and max, this seems like a waste of perfectly good memory space. Therefore I changed it to

import numpy as np
minmax = [np.inf, -np.inf]
for obj in objects:
    #...do stuff...
    val = obj.calc_value()
    if val < minmax[0]:
        minmax[0] = val
    if val > minmax[1]:
        minmax[1] = val
    #...do more stuff

which also work, but is a bit verbose. Sure, I could extract the four lines in the code into a function I guess, but...

I couldn't help but wonder, if there isn't a numpy function for this. Something like a "reverse" clip function. A function which, like clip, compares a value to an interval. But which does not return the (possibly changed) value so that it lies in the provided interval (which is what clip does), but rather returns the (possibly extended) interval that is needed so that the provided value lies in it.

import numpy as np
minmax = [np.inf, -np.inf]
for obj in objects:
    #...do stuff...
    minmax = np.reverse_clip(minmax, obj.calc_value())
    #...do more stuff

If there is, I'd love to hear about it. Also, any ideas how I could have found it without asking here? I looked at numpy's array methods, but couldn't find it there.

ElRudi
  • 2,122
  • 2
  • 18
  • 33
  • I guess I could change the 4 lines into 2, with `minmax[0] = min(minmax[0], val)`. That's better already, but I'm still curious about a `numpy` implementation. – ElRudi Jan 08 '20 at 12:51
  • 1
    Similar question: [numpy: function for simultaneous max() and min()](https://stackoverflow.com/questions/12200580/numpy-function-for-simultaneous-max-and-min) – khelwood Jan 08 '20 at 12:53

1 Answers1

0

You can reverse the sign on the first item and apply max on both, then change it back after the loop:

for obj in objects:
    i = obj.calc_value()
    minmax= map(max, zip([-i, i], minmax)) # using python
    minmax = np.vstack((minmax, [-i, i])).max(0) #using numpy
minmax *= np.array([-1, 1]) #using numpy
minmax = [i * j for i, j in zip(a1, [-1, 1])] # using python, or do list(a1) * np.array([-1, 1])
Tarifazo
  • 4,118
  • 1
  • 9
  • 22
  • Thanks @Mstaino for your answer! I wouldn't call it more readable, but it's definitely creative ;) I probably should have been more clear in my question but, due to the `[-i, i]` list, it's unfortunately not possible to forgo using a temporary variable here. – ElRudi Jan 08 '20 at 14:15
  • 1
    You can replace `[-i, i]` with `np.array([-1, 1]) * obj.calc_value()` to eliminate the temporary variable – Tarifazo Jan 08 '20 at 16:40
  • I personally find the `map` + `zip` combination very readable, and more performant for small operations. The `vstack` option less so, it is just to give you a different alternative – Tarifazo Jan 08 '20 at 16:43