I need to create an iterator from a range with either positive or negative steps, where start, stop, step are dependent on input. The problem: Range#step does not work with negative steps (10..5 and Range.new(10, 5).step(-1) are just empty). There is also Number#step but it does not respect exclusive range, which I require.
It's easy to build such an iterator specific for my purpose. But I think it would be nice if this could be in stdlib.
I noticed a few very similar iterators implemented in stdlib, maybe it would be usefull to merge some of them together? I'm nut sure about this, I just wanted to mention it.
Number::StepIterator used by Number#step Number#step with blockInt::UptoIterator](https://github.com/crystal-lang/crystal/blob/20655484b34a35ed1e69c8cad0525df8fac22323/src/int.cr#L503) forInt#upto`Int#upto with blockInt::DowntoIterator](https://github.com/crystal-lang/crystal/blob/20655484b34a35ed1e69c8cad0525df8fac22323/src/int.cr#L530) forInt#upto`Int#downto with blockRange::StepIterator for Range#stepRange#step with blockRange goes up. Use Number#step. If you need it exclusive, just subtract -1.
Number#step is not a real solution: a) it only works on numbers b) exclusiveness through -1 only works for integer steps.
I'd like to have it more generalized, that you can take whatever value implements #pred and/or #succ to create ascending and descending ranges.
This does not have to be implemented through Range, if that class is to stay a strictly mathematical interval. Although, for example ranges in Scala and Python can also be descending.
What I have in mind is, if you want to create a sequence from a start element to end element, it should not be limited to start < end. There are plenty of situations where you'd want it the other way around. And not necessarily limited to integers.
I think it should be similar to define a sequence of e.g. characters from g to a as from a to g - or strings or anything else that can form sequences.
sequence('a', 'g').step(3).to_a # => ['a', 'd', 'g']
sequence('g', 'a').step(3).to_a # why would this not be ['g', 'd', 'a'] ?
I'm calling it sequence to not disturbed the argument by a debate if this functionality should be part of Range or something else. The first line would be working if sequence is Range.new.
The basis for this are already there, but the #pred method to access predecessors is only used in Range#reverse_each. This method is no general solution because it has a fixed step size and if it did it'd still be tedious to check if start > stop, and if so, switch values of start and stop and remember to use #reverse_each if you need the values from the range in the required descending order.
I'd like there to be a way to create a sequence from a start element to an end element in a general way, without having to deal with the direction of this and with the possibility to use a custom step size.
@asterite Why Range is supposed to be only ascending? Descending ranges have valid use cases as well, and IMO there's no reason to handicap Range class in such a way.
@asterite hmm, are we ready to discuss the topic again after a year break? :)
Most helpful comment
Number#stepis not a real solution: a) it only works on numbers b) exclusiveness through-1only works for integer steps.I'd like to have it more generalized, that you can take whatever value implements
#predand/or#succto create ascending and descending ranges.This does not have to be implemented through
Range, if that class is to stay a strictly mathematical interval. Although, for example ranges in Scala and Python can also be descending.What I have in mind is, if you want to create a sequence from a start element to end element, it should not be limited to
start < end. There are plenty of situations where you'd want it the other way around. And not necessarily limited to integers.I think it should be similar to define a sequence of e.g. characters from
gtoaas fromatog- or strings or anything else that can form sequences.I'm calling it
sequenceto not disturbed the argument by a debate if this functionality should be part ofRangeor something else. The first line would be working ifsequenceisRange.new.The basis for this are already there, but the
#predmethod to access predecessors is only used inRange#reverse_each. This method is no general solution because it has a fixed step size and if it did it'd still be tedious to check ifstart > stop, and if so, switch values ofstartandstopand remember to use#reverse_eachif you need the values from the range in the required descending order.I'd like there to be a way to create a sequence from a start element to an end element in a general way, without having to deal with the direction of this and with the possibility to use a custom step size.