Is there a standard method in ruby similar to (1...4).to_a is [1,2,3,4] except reverse i.e. (4...1).to_a would be [4,3,2,1]?
I realize this can easily be defined via (1...4).to_a.reverse but it strikes me as odd that it is not already and 1) am I missing something? 2) if not, is there a functional/practical reason it is not already?
The easiest is probably this:
4.downto(1).to_a #=> [4, 3, 2, 1]
Alternatively you can use step:
4.step(1,-1).to_a #=> [4, 3, 2, 1]
Finally a rather obscure solution for fun:
(-4..-1).map(&:abs) #=> [4, 3, 2, 1]
(1...4) is a Range. Ranges in ruby are not like arrays; one if their advantages is you can create a range like
(1..1e9)
without taking up all of your machine's memory. Also, you can create this range:
r = (1.0...4.0)
Which means "the set of all floating point numbers from 1.0 to 4.0, including 1.0 but not 4.0"
In other words:
irb(main):013:0> r.include? 3.9999
=> true
irb(main):014:0> r.include? 3.99999999999
=> true
irb(main):015:0> r.include? 4.0
=> false
you can turn an integer Range into an array:
irb(main):022:0> (1..4).to_a
=> [1, 2, 3, 4]
but not a floating point range:
irb(main):023:0> (1.0...4.0).to_a
TypeError: can't iterate from Float
from (irb):23:in `each'
from (irb):23:in `to_a'
from (irb):23
from /home/mslade/rubygems1.9/bin/irb:12:in `<main>'
Because there is no natural way to iterate over floating point numbers. Instead you use #step:
irb(main):015:0> (1..4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]
irb(main):016:0> (1...4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
If you need to iterate backwards through a large integer range, use Integer#downto.
You could patch Range#to_a to automatically work with reverse like this:
class Range
alias :to_a_original :to_a
def reverse
Range.new(last, first)
end
def to_a
(first < last) ? to_a_original : reverse.to_a_original.reverse
end
end
Result:
(4..1).to_a
=> [4, 3, 2, 1]
This approach is called "re-opening" the class a.k.a. "monkey-patching". Some developers like this approach because it's adding helpful functionality, some dislike it because it's messing with Ruby core.)
Related
I've just started learning Ruby and Ruby on Rails and came across validation code that uses ranges:
validates_inclusion_of :age, :in => 21..99
validates_exclusion_of :age, :in => 0...21, :message => "Sorry, you must be over 21"
At first I thought the difference was in the inclusion of endpoints, but in the API docs I looked into, it didn't seem to matter whether it was .. or ...: it always included the endpoints.
However, I did some testing in irb and it seemed to indicate that .. includes both endpoints, while ... only included the lower bound but not the upper one. Is this correct?
The documentation for Range† says this:
Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.
So a..b is like a <= x <= b, whereas a...b is like a <= x < b.
Note that, while to_a on a Range of integers gives a collection of integers, a Range is not a set of values, but simply a pair of start/end values:
(1..5).include?(5) #=> true
(1...5).include?(5) #=> false
(1..4).include?(4.1) #=> false
(1...5).include?(4.1) #=> true
(1..4).to_a == (1...5).to_a #=> true
(1..4) == (1...5) #=> false
†The docs used to not include this, instead requiring reading the Pickaxe’s section on Ranges. Thanks to #MarkAmery (see below) for noting this update.
That is correct.
1.9.3p0 :005 > (1...10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
1.9.3p0 :006 > (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
The triple-dot syntax is less common, but is nicer than (1..10-1).to_a
The API docs now describe this behaviour:
Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.
-- http://ruby-doc.org/core-2.1.3/Range.html
In other words:
2.1.3 :001 > ('a'...'d').to_a
=> ["a", "b", "c"]
2.1.3 :002 > ('a'..'d').to_a
=> ["a", "b", "c", "d"]
a...b excludes the end value, while a..b includes the end value.
When working with integers, a...b behaves as a..b-1.
>> (-1...3).to_a
=> [-1, 0, 1, 2]
>> (-1..2).to_a
=> [-1, 0, 1, 2]
>> (-1..2).to_a == (-1...3).to_a
=> true
But really the ranges differ on a real number line.
>> (-1..2) == (-1...3)
=> false
You can see this when incrementing in fractional steps.
>> (-1..2).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]
>> (-1...3).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
.. and ... denote a range.
Just see it in irb:
ruby-1.9.2-p290 :032 > (1...2).each do puts "p" end
p
=> 1...2
ruby-1.9.2-p290 :033 > (1..2).each do puts "p" end
p
p
I think infinite enumerator is very convenient for writing FP style scripts but I have yet to find a comfortable way to construct such structure in Ruby.
I know I can construct it explicitly:
a = Enumerator.new do |y|
i = 0
loop do
y << i += 1
end
end
a.next #=> 1
a.next #=> 2
a.next #=> 3
...
but that's annoyingly wordy for such a simple structure.
Another approach is sort of a "hack" of using Float::INFINITY:
b = (1..Float::INFINITY).each
b = (1..1.0/0.0).each
These two are probably the least clumsy solution I can give. Although I'd like to know if there are some other more elegant way of constructing infinite enumerators. (By the way, why doesn't Ruby just make inf or infinity as a literal for Float::INFINITY?)
Use #to_enum or #lazy to convert your Range to an Enumerable. For example:
(1..Float::INFINITY).to_enum
(1..Float::INFINITY).lazy
I would personally create my own Ruby class for this.
class NaturalNumbers
def self.each
i = 0
loop { yield i += 1 }
end
end
NaturalNumbers.each do |i|
puts i
end
Ruby 2.7 introduced Enumerator#produce for creating an infinite enumerator from any block, which results in a very elegant, very functional way of implementing the original problem:
irb(main):001:0> NaturalNumbers = Enumerator.produce(0) { |x| x + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbd82d990>:each>
irb(main):002:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):003:0> _
... which - if you're a fan of numbered block parameters (another Ruby 2.7 feature) - can also be written as:
irb(main):006:0> NaturalNumbers = Enumerator.produce(0) { _1 + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbc8b08f0>:each>
irb(main):007:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):008:0> _
Is it possible to create ranges in ruby that exclude one or both of the endpoints. So handling the concept in mathematics of open and closed interval boundaries?
For example, can I define a range from 1.0 to 10.0 that excludes 1.0
Say (with pseudo-ruby)
range = [1.0...10.0)
range === 1.0
=> false
range === 10.0
=> true
The Range class in Ruby only supports closed and half-open (right-open) ranges. However, you can easily write your own.
Here's an example of a half-open range in Ruby:
range = 1.0...10.0
range === 1.0
# => true
range === 10.0
# => false
The total line count for the Ruby 1.9 compliant Range class in Rubinius is 238 lines of Ruby code. If you don't need your open range class to support every wrinkle, corner case, special case, idiosyncrasy, backwards-compatibility quirk and so on of the Ruby Language Specification you can get by with a lot less than that.
If you really only need to test for inclusion, then something like this should suffice:
class OpenRange
attr_reader :first, :last
def initialize(first, last, exclusion = {})
exclusion = { first: false, last: false }.merge(exclusion)
#first, #last, #first_exclusive, #last_exclusive = first, last, exclusion[:first], exclusion[:last]
end
def first_exclusive?; #first_exclusive end
def last_exclusive?; #last_exclusive end
def include?(other)
case [first_exclusive?, last_exclusive?]
when [true, true]
first < other && other < last
when [true, false]
first < other && other <= last
when [false, true]
first <= other && other < last
when [false, false]
first <= other && other <= last
end
end
alias_method :===, :include?
def to_s
"#{if first_exclusive? then '(' else '[' end}##first...##last#{if last_exclusive? then ')' else ']' end}"
end
alias_method :inspect, :to_s
end
you can exclude rightmost element of the range with .... See example below
(1..10).to_a # an array of numbers from 1 to 10 - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(1...10).to_a # an array of numbers from 1 to 9 - [1, 2, 3, 4, 5, 6, 7, 8, 9]
Ranges constructed using .. run from the start to the end inclusively. Those created using ... exclude the end value.
('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
('a'...'e').to_a #=> ["a", "b", "c", "d"]
See more here
You could easily write your own Range to exclude the start value too.
For float ranges:
(1.0..10.0).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
(1.0...10.0).step.to_a # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
(1.0..10.0).step(2.0).to_a # => [1.0, 3.0, 5.0, 7.0, 9.0]
(1.0...10.0).step(2.0).to_a # => [1.0, 3.0, 5.0, 7.0, 9.0]
a few years later but...
what about taking advantage of the facts that a case statement evaluates each criteria in order of appearance and follows the path based on it's first match.
In the sample 1.0 always does nothing even though it's technically a valid value for the second "when".
case myvalue
when 1.0
#Don't do anything (or do something else)
when 1.0...10.0
#Do whatever you do when value is inside range
# not inclusive of either end point
when 10.0
#Do whatever when 10.0 or greater
end
I've just started learning Ruby and Ruby on Rails and came across validation code that uses ranges:
validates_inclusion_of :age, :in => 21..99
validates_exclusion_of :age, :in => 0...21, :message => "Sorry, you must be over 21"
At first I thought the difference was in the inclusion of endpoints, but in the API docs I looked into, it didn't seem to matter whether it was .. or ...: it always included the endpoints.
However, I did some testing in irb and it seemed to indicate that .. includes both endpoints, while ... only included the lower bound but not the upper one. Is this correct?
The documentation for Range† says this:
Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.
So a..b is like a <= x <= b, whereas a...b is like a <= x < b.
Note that, while to_a on a Range of integers gives a collection of integers, a Range is not a set of values, but simply a pair of start/end values:
(1..5).include?(5) #=> true
(1...5).include?(5) #=> false
(1..4).include?(4.1) #=> false
(1...5).include?(4.1) #=> true
(1..4).to_a == (1...5).to_a #=> true
(1..4) == (1...5) #=> false
†The docs used to not include this, instead requiring reading the Pickaxe’s section on Ranges. Thanks to #MarkAmery (see below) for noting this update.
That is correct.
1.9.3p0 :005 > (1...10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
1.9.3p0 :006 > (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
The triple-dot syntax is less common, but is nicer than (1..10-1).to_a
The API docs now describe this behaviour:
Ranges constructed using .. run from the beginning to the end inclusively. Those created using ... exclude the end value.
-- http://ruby-doc.org/core-2.1.3/Range.html
In other words:
2.1.3 :001 > ('a'...'d').to_a
=> ["a", "b", "c"]
2.1.3 :002 > ('a'..'d').to_a
=> ["a", "b", "c", "d"]
a...b excludes the end value, while a..b includes the end value.
When working with integers, a...b behaves as a..b-1.
>> (-1...3).to_a
=> [-1, 0, 1, 2]
>> (-1..2).to_a
=> [-1, 0, 1, 2]
>> (-1..2).to_a == (-1...3).to_a
=> true
But really the ranges differ on a real number line.
>> (-1..2) == (-1...3)
=> false
You can see this when incrementing in fractional steps.
>> (-1..2).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0]
>> (-1...3).step(0.5).to_a
=> [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5]
.. and ... denote a range.
Just see it in irb:
ruby-1.9.2-p290 :032 > (1...2).each do puts "p" end
p
=> 1...2
ruby-1.9.2-p290 :033 > (1..2).each do puts "p" end
p
p
Right now I have
def min(array,starting,ending)
minimum = starting
for i in starting+1 ..ending
if array[i]<array[minimum]
minimum = i
end
end
return minimum
end
Is there a better "implementation" in Ruby? This one still looks c-ish.
Thanks.
If you want to find the index of the minimal element, you can use Enumerable#enum_for to
get an array of items-index pairs, and find the minimum of those with Enumerable#min (which will also be the minimum of the original array).
% irb
irb> require 'enumerator'
#=> true
irb> array = %w{ the quick brown fox jumped over the lazy dog }
#=> ["the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"]
irb> array.enum_for(:each_with_index).min
#=> ["brown", 2]
If you want to bound it to specific array indices:
irb> start = 3
#=> 3
irb> stop = 7
#=> 7
irb> array[start..stop].enum_for(:each_with_index).min
#=> ["fox", 0]
irb> array[start..stop].enum_for(:each_with_index).min.last + start
#=> 3
Basically that's the best you can do, though you can write it a bit more succinctly:
def minval(arr)
arr.inject {|acc,x| (acc && acc < x ? acc : x)}
end
There is a simpler way and it works for me in ruby 1.9.2:
a = [6, 9, 5, 3, 0, 6]
a.find_index a.min
This is the standard algorithm for finding the minimum element in an array, it can be better by having the array already be sorted before this function is called.
Otherwise I can't find a more efficient way of doing this. Specifically, linear time in big O notation is the best we can do.
If this isn't simply an academic question, why not just use Ruby's native sort method? It's implemented using a quicksort algorithm, and is considered to be pretty fast.
a = [3, 4, 5, 1, 7, 5]
a.sort![0] # => 1