Bracket notation on Ruby numbers - ruby

I found that when using bracket notation on the number 100 in Ruby, I get this:
irb(main):001:0> 100[0]
=> 0
irb(main):002:0> 100[1]
=> 0
irb(main):003:0> 100[2]
=> 1
So I assumed it was getting the digits, indexed like this:
NUMBER: 1|0|0
-----
INDEX: 2|1|0
I tried this on the number 789 with unexpected results.
irb(main):004:0> 789[0]
=> 1
irb(main):005:0> 789[1]
=> 0
irb(main):006:0> 789[2]
=> 1
I would expect it to return 9, then 8, then 7 if it was getting the digits. From this result, that is clearly not happening, so what exactly does using bracket notation on a number do?

These are the binary bits that you're pulling off. Another way to see this is using to_s with an argument indicating the desired base.
>> 789.to_s(2)
=> "1100010101"
String indexing is from left-to-right, so you can't compare [] on the string, but note how (from right-to-left) the digits are 1, 0, 1.
Here's the docs if you're interested: http://ruby-doc.org/core-1.9.3/Fixnum.html#method-i-5B-5D

Related

counting length of number and character inside string using regex in ruby

how to counting length of number and character inside string using regex in ruby?
if i have some case like this, how to resolve it?
example :
abc = "12345678a"
after counting using regex, i want get result like this :
number = 8
char = 1
how to do that?
Try following
abc = "12345678a"
abc.scan(/\d/).length
# => 8
abc.scan(/\D/).length
# => 1
No regex:
abc = "12345678a"
p abc.count("0-9") # => 8
p abc.count("a-zA-Z") # => 1
This is an optional, but I still think regex is better.
irb(main):051:0> number, char = abc.bytes.to_a.partition { |e| e >= 48 and e <= 57}
=> [[49, 50, 51, 52, 53, 54, 55, 56], [97]]
irb(main):053:0> number.count
=> 8
irb(main):054:0> char.count
=> 1
partition: Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.

Trim a trailing .0

I have an Excel column containing part numbers. Here is a sample
As you can see, it can be many different datatypes: Float, Int, and String. I am using roo gem to read the file. The problem is that roo interprets integer cells as Float, adding a trailing zero to them (16431 => 16431.0). I want to trim this trailing zero. I cannot use to_i because it will trim all the trailing numbers of the cells that require a decimal in them (the first row in the above example) and will cut everything after a string char in the String rows (the last row in the above example).
Currently, I have a a method that checks the last two characters of the cell and trims them if they are ".0"
def trim(row)
if row[0].to_s[-2..-1] == ".0"
row[0] = row[0].to_s[0..-3]
end
end
This works, but it feels terrible and hacky. What is the proper way of getting my Excel file contents into a Ruby data structure?
def trim num
i, f = num.to_i, num.to_f
i == f ? i : f
end
trim(2.5) # => 2.5
trim(23) # => 23
or, from string:
def convert x
Float(x)
i, f = x.to_i, x.to_f
i == f ? i : f
rescue ArgumentError
x
end
convert("fjf") # => "fjf"
convert("2.5") # => 2.5
convert("23") # => 23
convert("2.0") # => 2
convert("1.00") # => 1
convert("1.10") # => 1.1
For those using Rails, ActionView has the number_with_precision method that takes a strip_insignificant_zeros: true argument to handle this.
number_with_precision(13.00, precision: 2, strip_insignificant_zeros: true)
# => 13
number_with_precision(13.25, precision: 2, strip_insignificant_zeros: true)
# => 13.25
See the number_with_precision documentation for more information.
This should cover your needs in most cases: some_value.gsub(/(\.)0+$/, '').
It trims all trailing zeroes and a decimal point followed only by zeroes. Otherwise, it leaves the string alone.
It's also very performant, as it is entirely string-based, requiring no floating point or integer conversions, assuming your input value is already a string:
Loading development environment (Rails 3.2.19)
irb(main):001:0> '123.0'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):002:0> '123.000'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):003:0> '123.560'.gsub(/(\.)0+$/, '')
=> "123.560"
irb(main):004:0> '123.'.gsub(/(\.)0+$/, '')
=> "123."
irb(main):005:0> '123'.gsub(/(\.)0+$/, '')
=> "123"
irb(main):006:0> '100'.gsub(/(\.)0+$/, '')
=> "100"
irb(main):007:0> '127.0.0.1'.gsub(/(\.)0+$/, '')
=> "127.0.0.1"
irb(main):008:0> '123xzy45'.gsub(/(\.)0+$/, '')
=> "123xzy45"
irb(main):009:0> '123xzy45.0'.gsub(/(\.)0+$/, '')
=> "123xzy45"
irb(main):010:0> 'Bobby McGee'.gsub(/(\.)0+$/, '')
=> "Bobby McGee"
irb(main):011:0>
Numeric values are returned as type :float
def convert_cell(cell)
if cell.is_a?(Float)
i = cell.to_i
cell == i.to_f ? i : cell
else
cell
end
end
convert_cell("foobar") # => "foobar"
convert_cell(123) # => 123
convert_cell(123.4) # => 123.4

Ruby 'Range.last' does not give the last value. Why?

When using the triple dot notation in a ruby Range object, I get this:
(0...5).each{|n| p n}
0
1
2
3
4
When I use the 'last' method I get:
(0...5).last
=> 5
I would have expected 4
Is this is a bug? Or is there something I don't understand about the the concept of a Range object?
This is by design. The Ruby 2.0 documentation is more specific:
Note that with no arguments last will return the object that defines the end of the range even if exclude_end? is true.
(10..20).last #=> 20
(10...20).last #=> 20
(10..20).last(3) #=> [18, 19, 20]
(10...20).last(3) #=> [17, 18, 19]
As Stefan has answered your observed behavior is expected and documented.
If you want to obtain the last element which would be enumerated by the range without having to enumerate the whole range, you could use Enumerable#reverse_each
irb> (0...5).reverse_each.first
=> 4

How to get first n elements from Hash in ruby?

I have a Hash and i have sorted it using the values
#friends_comment_count.sort_by{|k,v| -v}
Now i only want to get hash of top five elements .. One way is to use a counter and break when its 5.
What is preferred way to do in ruby ?
Thanks
h = { 'a' => 10, 'b' => 20, 'c' => 30 }
# get the first two
p Hash[*h.sort_by { |k,v| -v }[0..1].flatten]
EDITED:
# get the first two (more concisely)
p Hash[h.sort_by { |k,v| -v }[0..1]]
Can't you just do something like:
h = {"test"=>"1", "test2"=>"2", "test3"=>"3"}
Then if you wanted the first 2:
p h.first(2).to_h
Result:
=> {"test"=>"1", "test2"=>"2"}
New to ruby myself (please be nice if I'm wrong guys!) but does this work?
#friends_comment_count.sort_by{|k,v| -v}.first 5
Works for me in IRB, if I've understood what you're trying to achieve correctly
You can't sort a Hash and that's why sort_by does NOT sort your Hash. It returns a sorted Array of Arrays.
In Ruby 2.2.0 and later, Enumerable#max_by takes an optional integer argument that makes it return an array instead of just one element. This means you can do:
h = { 'a' => 10, 'b' => 20, 'c' => 30 }
n = 2
p h.max_by(n, &:last).to_h # => {"b"=>20, "c"=>30}
Hashes are not ordered by nature (even thought in Ruby implementation they are). Try geting converting your Hash to Array and get [0,4] out of it

Ruby: How come the same strings have different hashcodes?

test = 'a'
test2 = '#a'.slice(0)
test3 = '#a'[1]
puts test.hash
puts test2.hash
puts test3.hash
Output:
100
64
97
Is this a bug or am I misunderstanding how the hash method works? Is there a way to fix this?
The results of these expressions are not all the same data. Ruby 1.8 integers contain character numbers for single character indexing. This has been changed in Ruby 1.9, but slice(0) returns the first character of the string '#', not 'a'.
In Ruby 1.8 (using irb):
irb(main):001:0> test = 'a'
=> "a"
irb(main):002:0> test2 = '#a'.slice(0)
=> 64
irb(main):003:0> test3 = '#a'[1]
=> 97
irb(main):004:0> test.hash
=> 100
irb(main):005:0> test2.hash
=> 129
irb(main):006:0> test3.hash
=> 195
In Ruby 1.9.1:
irb(main):001:0> test = 'a'
=> "a"
irb(main):002:0> test2 = '#a'.slice(0)
=> "#"
irb(main):003:0> test3 = '#a'[1]
=> "a"
irb(main):004:0> test.hash
=> 1365935838
irb(main):005:0> test2.hash
=> 347394336
irb(main):006:0> test3.hash
=> 1365935838
The reason is that each variable refers to different a object with its own unique hash code! The variable test is the string "a", test2 is the integer 64 (the character number of '#'), and test3 is the integer 97 ('a'). The surprise is probably that in Ruby, the elements of strings are integers, not strings or characters.
As maerics points out, unless you've defined your own hash method for the class you're using, the hash might simply be on the object itself, not its contents. That said, you can (and should) define your own hash method for any class where you define an equals method.
In Ruby, the String class already does this for you:
irb(main):001:0> test="a"
=> "a"
irb(main):002:0> test2="a"
=> "a"
irb(main):003:0> test.hash
=> 100
irb(main):004:0> test2.hash
=> 100
irb(main):005:0> test2[0]=test.slice(0)
=> 97
irb(main):006:0> test2
=> "a"
irb(main):007:0> test2.hash
=> 100
I haven't found an equivalent text for Ruby, but this page on Java gives an excellent algorithm for generating your own hash code that's not hard to copy for Ruby: http://www.javapractices.com/topic/TopicAction.do?Id=28

Resources