How to sort an array of floats in Ruby? - ruby

Just wondering how to sort an array of floats in Ruby, since "sort" and "sort!" only work for integer arrays.

Arrays of floats can certainly be sorted:
>> [6.2, 5.8, 1.1, 4.9, 13.4].sort
=> [1.1, 4.9, 5.8, 6.2, 13.4]
Maybe you have a nil in your array, which can't be sorted with anything.

You can sort a float array without any problem like :
irb(main):005:0> b = [2.0, 3.0, 1.0, 4.0]
=> [2.0, 3.0, 1.0, 4.0]
irb(main):006:0> b.sort
=> [1.0, 2.0, 3.0, 4.0]

perhaps you have something like this in your array and haven't noticed:
[1.0 , 3.0, 0/0, ...]
the 0/0 will give you a NaN which is impossible to compare with a Float... in this case you should try to
[2.3,nil,1].compact.sort
# => [1,2.3]
that or perhaps the same error with 1.0/0 wich yields infinity (but this error is detected by ruby)

Related

How to use a range with .. vs ... in Ruby [duplicate]

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

Array of Numbers and Half Numbers in Ruby

I'm trying to populate an array with sizes that are measured in whole and half numbers (i.e. 10, 10.5, 11, 11.5, 12). So far I have:
(10..12).map{ |size| [size, size + 0.5] }.flatten[0...-1]
Does a more eloquent way of doing this exist in Ruby without having to flatten and remove the last element?
My personal favorite:
>> (10..12).step(0.5).to_a
=> [10.0, 10.5, 11.0, 11.5, 12.0]
You can use lambdas (notice that it outputs floats) - I'll let you decide if that is more eloquent.
irb(main):001:0> fn = ->(x, y) { (x*2..y*2).map { |i| i / 2.0 } }
=> #<Proc:0x007fa782b0a4b0#(irb):1 (lambda)>
irb(main):002:0> fn.call(10, 12)
=> [10.0, 10.5, 11.0, 11.5, 12.0]
I've assumed you want the values in the returned array to alternate between Fixnum and Float, as in your example:
(10..12).flat_map { |size| [size, size + 0.5] }.tap { |a| a.pop }
#=> [10, 10.5, 11, 11.5, 12]

Open ranges in Ruby using floats?

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

Reverse `...` method Ruby

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.)

Difference between '..' (double-dot) and '...' (triple-dot) in range generation?

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

Resources