1

For reasons that I cannot understand, Python3 still doesn't supply a built-in range() like generator object for floats.

So enter numpy.arange(). However that function returns an array. Arrays of floats simply for iteration make no fundamental sense when they are very large, which for my uses are common.

Is there a function within numpy that supplies a generator version of arange(), or am I left to code it by hand?

alife
  • 411
  • 4
  • 14
  • I don't think there's one...? – gmds May 09 '19 at 01:02
  • A selection of Google searches doesn't list one either. Not that it'd be hard to build - five lines, max. – Green Cloak Guy May 09 '19 at 01:14
  • There's an existing answer and discussion [here](https://stackoverflow.com/questions/7267226/range-for-floats) – Tls Chris May 09 '19 at 09:35
  • Ok, as I mentioned, I asked if I had to code one by hand. But my list of misgivings with this particular language seems to be growing, and now with numpy. That's really an odd omission, particularly since they went out of their way to not have a for(;;)-esque equivalency. And especially when they created an idiom _**already**_ for integers with `range()`. Law of Least Surprise, etc... – alife May 09 '19 at 13:13
  • @TlsChris, I can live with numpy, because its now more or less ubiquitous enough to be considered 'laguage proper', but to have to import some relatively unknown utilities like `more_itertools.numeric_range`, for something so basic seems nuts. I suppose I should be grateful that function seems to be free of artifacts and error accumulation. – alife May 09 '19 at 13:26
  • Generators feed other generators until the final operation produces a list. They are an iteration tool. `numpy` doesn't do iterations - at least not well. You are supposed to pass whole arrays from one compiled operation to the next. Generators are rarely used with numpy. – hpaulj May 09 '19 at 20:34
  • @hpaulj, understood. Thanks. I can't understand the reasoning however, particularly for what seems to be portrayed as a world-class language. I'm clearly "missing the boat" on the design of this thing. Not allowing overloading of `__init__()`? No find control of threading? I'm going to recommend we move on to another language for our expert system research. And I'm certainly going to push our district's high school similarly away. Languages shouldn't be designed with aggravation in mind. Thanks all. – alife May 11 '19 at 18:56

1 Answers1

1

The lack of float support in range doesn't seem like a big fault. The suggested link shows all kinds of ways of generating the numbers. They also point out the tricky issues. numeric_range also discusses these issues.

arange can handle float steps, but with a warning.

In [79]: np.arange(0,10,1.25)                                                   
Out[79]: array([0.  , 1.25, 2.5 , 3.75, 5.  , 6.25, 7.5 , 8.75])

linspace is recommended instead, with better end point control. For what it's worth MATLAB also has a linspace function.

In [80]: np.linspace(0,10,9)                                                    
Out[80]: array([ 0.  ,  1.25,  2.5 ,  3.75,  5.  ,  6.25,  7.5 ,  8.75, 10.  ])

But my gut feeling is that scaling range output would be the cleanest generator:

In [81]: g = (i*1.25 for i in range(9))   # generator expression                                 
In [82]: list(g)                                                                
Out[82]: [0.0, 1.25, 2.5, 3.75, 5.0, 6.25, 7.5, 8.75, 10.0]

One of the link answers suggests itertools.takewhile:

In [83]: import itertools                                                       
In [86]: g = itertools.takewhile(lambda x: x<10, itertools.count(0,1.25))       
In [87]: list(g)                                                                
Out[87]: [0, 1.25, 2.5, 3.75, 5.0, 6.25, 7.5, 8.75]

Both of these answers feed one generator to another, consistent with the philosophy I cited in my comment. Building complex actions by stringing together smaller building blocks is typical Python, and even more so numpy.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • 1
    Well, as I pointed out, the returning of lists and arrays are outside what I'm interested in, so `arange()` and `linspace()` are out. Also, this isn't a forum, so I'll temper my distaste for what I'm seeing in this language somewhat except perhaps to say that the idiom was already established in `range()`. They already _went out of their way_ to change `range()` to a generator, so there are two sins here. 1. Not having an `arange()` in the first place as a built-in, and 2. (_my_ chief complaint) not having such a facility as a generator. – alife May 11 '19 at 21:57
  • There's a _reason_ that `range()` was changed (instead of relying upon `xrange()`). That sensibility should have carried through to numpy, which didn't even offer an "xarange()" of some kind. Again, whether or not I understand the nature of a language is outside the question-and-answer nature of this site, so I'll apologize for this diversion and simply thank you all for your replies....they were helpful in my decision making. – alife May 11 '19 at 21:58
  • 1
    I don't understand why you want a `numpy` function to behave like a base Python one. The purpose of `arange` is to create a `numpy.ndarray`. This has it's own storage (distinct from python lists), and fast C level iterators (and other methods). Python level iteration through a `ndarray` should well down the list of priorities. – hpaulj May 12 '19 at 03:31
  • There are many cases in our models where we have to loop through uniformly spaced floating point increments, many would result in larger than 100,000 floats at a time. It's unacceptable to me to create a structure in memory just to hold iterative values whose purposes are shortlived. Perhaps there are some cases where that's acceptable, but it's certainly not in our case. Yes, it can be done by hand; I'm still alarmed however because it seems that entire subsystems (numpy) are designed around this model. There seems to be a philosophical disconnect here; something not solvable in comments. – alife May 12 '19 at 15:41
  • 1
    `numpy` is the wrong numeric tool for this kind of looping. Quite a part from memory use, you'll be disappointed with the speed. – hpaulj May 12 '19 at 16:00