Why does `"0a".to_i(16)` return `10`? - ruby

I'm confused about the optional argument for to_i.
Specifically, what "base" means, and how it impacts the method in this example:
"0a".to_i(16) #=> 10
I have trouble with the optional argument in regards to the string the method is called on. I thought that the return value would just be an integer value of 0.

Simple answer: It's because 0a or a in Hexadecimal is equal to 10 in Decimal.
And base, in other word Radix means the number of unique digits in a numeral system.
In Decimal, we have 0 to 9, 10 digits to represent numbers.
In Hexadecimal, there're 16 digits instead, apart from 0 to 9, we use a to f to represent the conceptual numbers of 10 to 15.
You can test it like this:
"a".to_i(16)
#=> 10
"b".to_i(16)
#=> 11
"f".to_i(16)
#=> 15
"g".to_i(16)
#=> 0 # Because it's not a correct hexadecimal digit/number.
'2c'.to_i(16)
#=> 44
'2CH2'.to_i(16)
#=> 44 # Extraneous characters past the end of a valid number are ignored, and it's case insensitive.
9.to_s.to_i(16)
#=> 9
10.to_s.to_i(16)
#=> 16
In other words, 10 in Decimal is equal to a in Hexadecimal.
And 10 in Hexadecimal is equal to 16 in Decimal. (Doc for to_i)
Note that usually we use 0x precede to Hexadecimal numbers:
"0xa".to_i(16)
#=> 10
"0x100".to_i(16)
#=> 256
Btw, you can just use these representations in Ruby:
num_hex = 0x100
#=> 256
num_bin = 0b100
#=> 4
num_oct = 0o100
#=> 64
num_dec = 0d100
#=> 100
Hexadecimal, binary, octonary, decimal (this one, 0d is superfluous of course, just use in some cases for clarification.)

Related

Convert a two-letter String to a 3-digit number

I am working on a software problem and I found myself needing to convert a 2-letter string to a 3-digit number. We're talking about English alphabet only (26 letters).
So essentially I need to convert something like AA, AR, ZF, ZZ etc. to a number in the range 0-999.
We have 676 combinations of letters and 1000 numbers, so the range is covered.
Now, I could just write up a map manually, saying that AA = 1, AB = 2 etc., but I was wondering if maybe there is a better, more "mathematical" or "logical" solution to this.
The order of numbers is of course not relevant, as long as the conversion from letters to numbers is unique and always yields the same results.
The conversion should work both ways (from letters to numbers and from numbers to letters).
Does anyone have an idea?
Thanks a lot
Treat A-Z as 1-26 in base 27, with 0 reserved for blanks.
E.g. 'CD' -> 3 * 27 + 4 = 85
85 -> 85 / 27, 85 % 27 = 3, 4 = C, D
If you don’t have to use consecutive numbers, you can view a two-letter string as a 36-based number. So, you can just use the int function to convert it into an Integer.
int('AA', 36) # 370
int('AB', 36) # 371
#...
int('ZY', 36) # 1294
int('ZZ', 36) # 1295
As for how to convert the number back to a string, you can refer to the method on How to convert an integer to a string in any base?
#furry12 because the diff between the first number and the last one is 1295-370=925<999. It is quite lucky, so you can minus every number for like 300, the results will be in the range of 0-999
def str2num(s):
return int(s, 36) - 300
print(str2num('AA')) # 70
print(str2num('ZZ')) # 995

Returning the highest and lowest numbers in a string: Ruby

Not sure what I'm doing incorrect but I seem to be getting it woefully wrong.
The question is, you are given a string of space separated numbers, and have to return the highest and lowest number.
Note:
All numbers are valid Int32, no need to validate them.
There will always be at least one number in the input string.
Output string must be two numbers separated by a single space, and highest number is first.
def high_and_low(numbers)
# numbers contains a string of space seperated numbers
#return the highest and lowest number
numbers.minmax { |a, b| a.length <=> b.length }
end
Output:
`high_and_low': undefined method `minmax' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String
minmax is not implemented for a string. You need to split your string into an array first. But note that split will return an array of strings, not numbers, you will need to translate the strings to integers (to_i) in the next step.
Because minmax returns the values in the opposite order than required, you need to rotate the array with reverse and then just join those numbers with whitespace for the final result.
numbers = "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"
def high_and_low(numbers)
numbers.split.minmax_by(&:to_i).reverse.join(' ')
end
high_and_low(numbers)
#=> "542 -214"
How about:
numbers_array = numbers.split(' ')
"#{numbers_array.max} #{numbers_array.min}"
If you're starting with a string of numbers you may have to cast the .to_i after the call to split.
In that case:
numbers_array = numbers.split(' ').map { |n| n.to_i }
"#{numbers_array.max} #{numbers_array.min}"
As you're starting with a String, you must turn it into an Array to cast minmax on it.
Also, make sure to compare Integers by casting .map(&:to_i) on the Array; otherwise you'd compare the code-point instead of the numerical value.
def get_maxmin(string)
string.split(' ')
.map(&:to_i)
.minmax
.reverse
.join(' ')
end
There is no need to convert the string to an array.
def high_and_low(str)
str.gsub(/-?\d+/).
reduce([-Float::INFINITY, Float::INFINITY]) do |(mx,mn),s|
n = s.to_i
[[mx,n].max, [mn,n].min]
end
end
high_and_low "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"
#=> [542, -214]
Demo
This uses the form of String#gsub that has one argument and no block, so it returns an enumerator that I've chained to Enumerable#reduce (a.k.a. inject). gsub therefore merely generates matches of the regular expression /-?\d+/ and performs no substitutions.
My solution to this kata
def high_and_low(numbers)
numbers.split.map(&:to_i).minmax.reverse.join(' ')
end
Test.assert_equals(high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6"), "542 -214")
#Test Passed: Value == "542 -214"
Some docs about methods:
String#split Array#map Array#minmax Array#reverse Array#join
More about Symbol#to_proc
numbers.split.map(&:to_i) is same as number.split.map { |p| p.to_i }
But "minmax_by(&:to_i)" looks better, for sure I guess.

`to_i` method with base value as parameter in ruby

Can anyone explain how base parameter works when calling to_i with the following examples?
'2'.to_i(2) #=> 0
'3'.to_i(2) #=> 0
'12'.to_i(2) #=> 1
'122'.to_i(2) #=> 1
'20'.to_i(2) #=> 0
'21'.to_i(2) #=> 0
I do not understand how it's actually working. Can anyone explain please?
It is the same reason that '54thousand'.to_i is 54: to_i reads until it finds end of string or an invalid digit.
In binary (base 2), the only valid digits are 0 and 1. Thus, because 2 is invalid, '122'.to_i(2) is identical to '1'.to_i(2). Also, '2'.to_i(2) is identical to ''.to_i(2), which is rather intuitively 0.
base, in other word Radix means the number of unique digits in a numeral system.
In Decimal, we have 0 to 9, 10 digits to represent numbers.
You are using 2 as parameter, that means Binary, so there're only 0 and 1 working.
From the Doc of to_i:
Returns the result of interpreting leading characters in str as an
integer base base (between 2 and 36). Extraneous characters past the
end of a valid number are ignored. If there is not a valid number at
the start of str, 0 is returned. This method never raises an
exception when base is valid.
You can use these number representations directly in Ruby:
num_hex = 0x100
#=> 256
num_bin = 0b100
#=> 4
num_oct = 0o100
#=> 64
num_dec = 0d100
#=> 100

Ruby's String#hex confusion

I've found it weird that String#hex in Ruby doesn't return the right hex value for a given char. I might be misunderstanding the method, but take the following example:
'a'.hex
=> 10
Whereas the right hex value for 'a' would be 61:
'a'.unpack('H*')
=> 61
Am I missing something? What's hex for? Any hints appreciated!
Thanks
String#hex doesn't give you the ASCII index of a character, it's for transforming a base-16 number (hexadecimal) from a string to an integer:
% ri String\#hex
String#hex
(from ruby site)
------------------------------------------------------------------------------
str.hex -> integer
------------------------------------------------------------------------------
Treats leading characters from str as a string of hexadecimal digits
(with an optional sign and an optional 0x) and returns the
corresponding number. Zero is returned on error.
"0x0a".hex #=> 10
"-1234".hex #=> -4660
"0".hex #=> 0
"wombat".hex #=> 0
So it uses the normal mapping:
'0'.hex #=> 0
'1'.hex #=> 1
...
'9'.hex #=> 9
'a'.hex #=> 10 == 0xA
'b'.hex #=> 11
...
'f'.hex #=> 15 == 0xF == 0x0F
'10'.hex #=> 16 == 0x10
'11'.hex #=> 17 == 0x11
...
'ff'.hex #=> 255 == 0xFF
It's very similar to String#to_i when using base 16:
'0xff'.to_i(16) #=> 255
'FF'.to_i(16) #=> 255
'-FF'.to_i(16) #=> -255
From the docs:
% ri String\#to_i
String#to_i
(from ruby site)
------------------------------------------------------------------------------
str.to_i(base=10) -> integer
------------------------------------------------------------------------------
Returns the result of interpreting leading characters in str as an
integer base base (between 2 and 36). Extraneous characters past the
end of a valid number are ignored. If there is not a valid number at the start
of str, 0 is returned. This method never raises an exception
when base is valid.
"12345".to_i #=> 12345
"99 red balloons".to_i #=> 99
"0a".to_i #=> 0
"0a".to_i(16) #=> 10
"hello".to_i #=> 0
"1100101".to_i(2) #=> 101
"1100101".to_i(8) #=> 294977
"1100101".to_i(10) #=> 1100101
"1100101".to_i(16) #=> 17826049
One more advantage over hex method. '10-0' to 256.
Consider you want to compare'100' > '20'. Should return true but return false. Use '100'.hex >'20'.hex. Returns true. Which is more accurate.

How to find remainder of a division in Ruby?

I'm trying to get the remainder of a division using Ruby.
Let's say we're trying to divide 208 by 11.
The final should be "18 with a remainder of 10"...what I ultimately need is that 10.
Here's what I've got so far, but it chokes in this use case (saying the remainder is 0).
division = 208.to_f / 11
rounded = (division*10).ceil/10.0
remainder = rounded.round(1).to_s.last.to_i
The modulo operator:
> 208 % 11
=> 10
If you need just the integer portion, use integers with the / operator, or the Numeric#div method:
quotient = 208 / 11
#=> 18
quotient = 208.0.div 11
#=> 18
If you need just the remainder, use the % operator or the Numeric#modulo method:
modulus = 208 % 11
#=> 10
modulus = 208.0.modulo 11
#=> 10.0
If you need both, use the Numeric#divmod method. This even works if either the receiver or argument is a float:
quotient, modulus = 208.divmod(11)
#=> [18, 10]
208.0.divmod(11)
#=> [18, 10.0]
208.divmod(11.0)
#=> [18, 10.0]
Also of interest is the Numeric#remainder method. The differences between all of these can be seen in the documentation for divmod.
please use Numeric#remainder because mod is not remainder
Modulo:
5.modulo(3)
#=> 2
5.modulo(-3)
#=> -1
Remainder:
5.remainder(3)
#=> 2
5.remainder(-3)
#=> 2
here is the link discussing the problem
https://rob.conery.io/2018/08/21/mod-and-remainder-are-not-the-same/

Resources