Ruby how to increment a string number - ruby

How can I confidently increment a string number in Ruby? I understand I can call "1".next and produce "2" but this does not work for negative numbers.
"-3".next
=> "-4"
How can I call to increment both positive and negative string digits? I want to return value as String.

You can convert that string to integer, call #next and then convert it back to string
'-3'.to_i.next.to_s

You could just do ("-3".to_i + 1).to_s but that does not account for float values (if you cared for that). You can call gsub with a block and match with regex to convert and increment. next does not work for negatives as it only evaluates the rightmost numeric and pays no attention to the minus character. The below matches for integers or floats and increments them based on the integer type:
INCREMENTAL = 1
def increment_str(str)
str.gsub(/(-)?\d+(.\d+)?/) { |x| x.include?(".") ? x.to_f + INCREMENTAL : x.to_i + INCREMENTAL }
end
increment_str("-3") => "-2"
increment_str("3") => "4"
increment_str("-3.0") => "-2.0"
increment_str("3.0") => "4.0"

Your answer depends on whether the input is integer or float. In each case, cast it to the appropriate numeric type (to_i to to_f), increment by 1, and cast back to string. For example:
['-1.23', '-1', '0', '1', '1.23'].each do |str|
int_str_plus_1 = (str.to_i + 1).to_s
float_str_plus_1 = (str.to_f + 1).to_s
puts [str, int_str_plus_1, float_str_plus_1].join("\t")
end
Prints:
-1.23 0 -0.22999999999999998
-1 0 0.0
0 1 1.0
1 2 2.0
1.23 2 2.23

Related

Ruby: Am I using the correct scope?

I come from a JavaScript background and wrote this similar to how I would in javascript. I am writing it in Ruby.
This is a codewars exercise.
n being 0 and 1 returns 0.00 and 1.00 as expected. Every other positive natural number returns 0.
# Task:
# Your task is to write a function which returns the sum of following series upto nth term(parameter).
# Series: 1 + 1/4 + 1/7 + 1/10 + 1/13 + 1/16 +...
# Rules:
# You need to round the answer to 2 decimal places and return it as String.
# If the given value is 0 then it should return 0.00
# You will only be given Natural Numbers as arguments.
# Examples:
# SeriesSum(1) => 1 = "1.00"
# SeriesSum(2) => 1 + 1/4 = "1.25"
# SeriesSum(5) => 1 + 1/4 + 1/7 + 1/10 + 1/13 = "1.57"
def series_sum(n)
sum = 0
if n == 0
return 0.00
elsif n == 1
return 1.00
else
n.times do |i|
if i == 1
sum += 1
break
end
sum += 1/( 1 + (3 * (i - 1)) )
end
end
return sum
end
puts series_sum(0)
puts series_sum(1)
puts series_sum(2)
puts series_sum(4)
puts series_sum(5)
A couple of things to note:
- Ruby has reduce method that can sum up a list of numbers: https://apidock.com/ruby/Enumerable/reduce
- You don't need to explicitly return from your method. Ruby automatically returns the last statement in your method.
I've modified your solution, and this should work:
def series_sum(n)
if n > 1
sum = (1..n).inject { |sum, i| sum + (1/(1.to_f + (3 * (i - 1)))) }
else
sum = n
end
'%.2f' % sum
end
When you are expecting a decimal number in a division, always make sure that either the numerator or the denominator is in float, hence the reason for the 1.to_f.
'%.2f' is a string format to ensure the final answer is returned in 2 decimal places.
There are two parts to this question.
How to display an operation's result as a float value?
1/2 # this will give 0
1.0/2 # this will give 0.5
How to limit a float value to 2 decimal places?
You can use the round function
22.0/7 # this will give pi value - 3.142857142857143
(22.0/7).round(2) # this will give 3.14
The two answers above can be combined to get your answer. I would leave it as an exercise for you to come up with the exact code to solve your problem.
def series_sum(n)
return "0.00" if n.zero?
sprintf("%.2f", (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2))
end
series_sum(0) #=> "0.00"
series_sum(1) #=> "1.00"
series_sum(2) #=> "1.25"
series_sum(3) #=> "1.39"
series_sum(4) #=> "1.49"
series_sum(5) #=> "1.57"
See Kernel#sprintf. One could alternatively use String%, which shares sprintf's formatting directives:
"%.2f" % (0..n-1).sum { |m| 1.fdiv(3*m+1) }.round(2)
I am not aware of the existence of a closed-form expression for this partial sum. Though not relevant to the question, this partial sum can be shown to be divergent.

Generating random number of length 6 with SecureRandom in Ruby

I tried SecureRandom.random_number(9**6) but it sometimes returns 5 and sometimes 6 numbers. I'd want it to be a length of 6 consistently. I would also prefer it in the format like SecureRandom.random_number(9**6) without using syntax like 6.times.map so that it's easier to be stubbed in my controller test.
You can do it with math:
(SecureRandom.random_number(9e5) + 1e5).to_i
Then verify:
100000.times.map do
(SecureRandom.random_number(9e5) + 1e5).to_i
end.map { |v| v.to_s.length }.uniq
# => [6]
This produces values in the range 100000..999999:
10000000.times.map do
(SecureRandom.random_number(9e5) + 1e5).to_i
end.minmax
# => [100000, 999999]
If you need this in a more concise format, just roll it into a method:
def six_digit_rand
(SecureRandom.random_number(9e5) + 1e5).to_i
end
To generate a random, 6-digit string:
# This generates a 6-digit string, where the
# minimum possible value is "000000", and the
# maximum possible value is "999999"
SecureRandom.random_number(10**6).to_s.rjust(6, '0')
Here's more detail of what's happening, shown by breaking the single line into multiple lines with explaining variables:
# Calculate the upper bound for the random number generator
# upper_bound = 1,000,000
upper_bound = 10**6
# n will be an integer with a minimum possible value of 0,
# and a maximum possible value of 999,999
n = SecureRandom.random_number(upper_bound)
# Convert the integer n to a string
# unpadded_str will be "0" if n == 0
# unpadded_str will be "999999" if n == 999999
unpadded_str = n.to_s
# Pad the string with leading zeroes if it is less than
# 6 digits long.
# "0" would be padded to "000000"
# "123" would be padded to "000123"
# "999999" would not be padded, and remains unchanged as "999999"
padded_str = unpadded_str.rjust(6, '0')
Docs to Ruby SecureRand, lot of cool tricks here.
Specific to this question I would say: (SecureRandom.random_number * 1000000).to_i
Docs: random_number(n=0)
If 0 is given or an argument is not given, ::random_number returns a float: 0.0 <= ::random_number < 1.0.
Then multiply by 6 decimal places (* 1000000) and truncate the decimals (.to_i)
If letters are okay, I prefer .hex:
SecureRandom.hex(3) #=> "e15b05"
Docs:
hex(n=nil)
::hex generates a random hexadecimal string.
The argument n specifies the length, in bytes, of the random number to
be generated. The length of the resulting hexadecimal string is twice
n.
If n is not specified or is nil, 16 is assumed. It may be larger in
future.
The result may contain 0-9 and a-f.
Other options:
SecureRandom.uuid #=> "3f780c86-6897-457e-9d0b-ef3963fbc0a8"
SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
For Rails apps creating a barcode or uid with an object you can do something like this in the object model file:
before_create :generate_barcode
def generate_barcode
begin
return if self.barcode.present?
self.barcode = SecureRandom.hex.upcase
end while self.class.exists?(barcode: barcode)
end
SecureRandom.random_number(n) gives a random value between 0 to n. You can achieve it using rand function.
2.3.1 :025 > rand(10**5..10**6-1)
=> 742840
rand(a..b) gives a random number between a and b. Here, you always get a 6 digit random number between 10^5 and 10^6-1.

Find the combinations of a given encoded string using Ruby

I was asked this question during an interview and I couldn't come up with a satisfactory solution for it. Would appreciate if anybody could give some pointers.
Given a mapping like
mapping = {"A" => 1, "B" => 2, "C" => 3..... "Z" => 26}
encode("A") == "1"
encode("BA") == "21"
encode("ABC") == "123"
encode("") == ""
decode("1") == ["A"] -> 1
decode("21") == ["BA", "V"] -> 2
decode("123") == ["ABC", "JC", "AX"] -> 3
decode("012") == [] -> 0
decode("") == [""] -> 1
decode("102") == ["JB"] -> 1
numDecode(X) == len(decode(X))
numDecode("1") == 1
numDecode("21") == 2
numDecode("123") == 3
numDecode("") == 1
numDecode("102") == 1
numDecode("012") == 0
We need a numDecode method which gives the length of unique solution array.
Updated :
Given a mapping like :
mapping = {"A" => 1, "B" => 2, "C" => 3..... "Z" => 26}
Suppose we are given a string as "A" the it can be encoded as : "1"
encode("A") should return "1"
encode("BA") should return "21" as if mapping is a hash then B has a value of 2, A has a value of 1.
encode("ABC") should return "123" as mapping["A" is 1, mapping["B"] is 2, and mapping["C"] is 3.
encode("") should return "" as it is not in mapping.
Now if decode("1") is called then it should return an array with one element i.e. ["A"] as key matching with 1 as value in mapping is "A".
decode("") should return an array with empty string i.e. [""].
decode("21") should return an array ["BA", "U"] as 2 is "B", 1 is "A" and "U" is 21 in mapping.
decode("012") should return an empty array as string starts with "0" which is not in mapping keys.
decode("102") should return an array as ["JB"] as "10" is J and "2" is B.
And finally numDecode should return the count of unique decoded strings in array. So,
numDecode(X) == len(decode(X))
numDecode("1") == 1
numDecode("21") == 2
numDecode("123") == 3
numDecode("") == 1
numDecode("102") == 1
numDecode("012") == 0
This is an interesting question, and the interview technique that goes with it is most likely to see how far the critical thinking goes. A good interviewer would probably not expect a single canonically correct answer.
If you get as far as a recursive decode solution that you then enumerate, then you are doing well IMO (at least I'd hire most candidates who could demonstrate clearly thinking through a piece of recursive code at interview!)
Having said that, one key hint is that the question asks for a num_decode function, not necessarily for implementations of encode and decode.
There is a deeper understanding and structure accessible here, that can be gained from analysing the permutations and combinations. It allows you to write a num_decode function that can handle long strings with millions of possible answers, without filling memory or taking hours to enumerate all possibilities.
First note that any set of separate ambiguous encoding multiply the number of possibilities for the whole string:
1920 -> 19 is ambiguous 'AI' or 'S' -> 'AIT' or 'ST'
192011 -> 11 is also ambiguous 'AA' or 'K' -> 'AITAA', 'AITK', 'STAA', 'STK'
Here 19 has two possible interpretations, and 11 also has two. A string with both of these separate instances of ambiguous codings has 2 * 2 == 4 valid combinations.
Each independent section of ambiguous coding multiplies the size of the whole set of decode values by the number of possibilities that it represents.
Next how to deal with longer ambiguous sections. What happens when you add an ambiguous digit to an ambiguous sequence:
11 -> 'AA' or 'K' -> 2
111 -> 'AAA', 'AK', 'KA' -> 3
1111 -> 'AAAA', 'AAK', 'AKA', 'KAA', 'KK' -> 5
11111 -> 'AAAAA', 'AAAK', 'AAKA', 'AKAA', 'AKK', 'KAAA', 'KAK', 'KKA' -> 8
2,3,5,8 should look familiar, it is the Fibonacci sequence, what's going on? The answer is that adding one digit to the sequence allows all the previous combinations plus those of the sub-sequence before that. By adding a digit 1 to the sequence 1111 you can either interpret it as 1111(1) or 111(11) - so you can add together the number of possibilities in 1111 and 111 to get the number of possibilities in 11111. That is, N(i) = N(i-1) + N(i-2) which is how to construct the Fibonacci series.
So, if we can detect ambiguous coding sequences, and get their length, we can now calculate the number of possible decodes, without actually doing the decode:
# A caching Fibonacci sequence generator
def fib n
#fibcache ||= []
return #fibcache[n] if #fibcache[n]
a = b = 1
n.times do |i|
a, b = b, a + b
#fibcache[i+1] = a
end
#fibcache[n]
end
def num_decode encoded
# Check that we don't have invalid sequences, raising here, but you
# could technically return 0 and be correct according to question
if encoded.match(/[^0-9]/) || encoded.match(/(?<![12])0/)
raise ArgumentError, "Not a valid encoded sequence"
end
# The look-ahead assertion ensures we don't match
# a '1' or '2' that is needed by a '10' or '20'
ambiguous = encoded.scan(/[12]*1[789]|[12]+[123456](?![0])/)
ambiguous.inject(1) { |n,s| n * fib(s.length) }
end
# A few examples:
num_decode('') # => 1
num_decode('1') # => 1
num_decode('12') # => 2
num_decode('120') # => 1
num_decode('12121212') # => 34
num_decode('1212121212121212121212121211212121212121') # => 165580141
It is relatively short strings like the last one which foil attempts to enumerate
the possibilities directly by decoding.
The regex in the scan took a little experimentation to get right. Adding 7,8 or 9 is ambiguous after a 1, but not after a 2. You also want to avoid counting a 1 or 2 directly before a 0 as part of an ambiguous sequence because 10 or 20 have no other interpretations. I think I made about a dozen attempts at the regex before settling on the current version (which I believe to be correct, but I did keep finding exceptions to correct values most times I tested the first versions).
Finally, as an exercise, it should be possible to use this code as the basis from which to write a decoder that directly output the Nth possible decoding (or even one that enumerated them lazily from any starting point, without requiring excessive memory or CPU time).
Here's a recursive solution:
$mapping = Hash[(0..25).map { |i| [('A'.ord+i).chr,i+1] }]
$itoa = Hash[$mapping.to_a.map { |pair| pair.reverse.map(&:to_s) }]
def decode( str )
return [''] if str.empty?
return $itoa.key?(str) ? [$itoa[str]] : nil if str.length == 1
retval = []
0.upto(str.length-1) do |i|
word = $itoa[str[0..i]] or next
tails = decode(str[i+1..-1]) or next
retval.concat tails.map { |tail| word + tail }
end
return retval
end
Some sample output:
p decode('1') # ["A"]
p decode('21') # ["BA", "U"]
p decode('123') # ["ABC", "AW", "LC"]
p decode('012') # []
p decode('') # [""]
p decode('102') # ["JB"]
p decode('12345') # ["ABCDE", "AWDE", "LCDE"]
Note differences between this output and the question. E.g. The 21st letter of the alphabet is "U", not "V". etc.
#he = Hash[("A".."Z").to_a.zip((1..26).to_a.map(&:to_s))]
# => {"A"=>"1", "B"=>"2",...,"Z"=>"26"}
#hd = #he.invert # => {"1"=>"A", "2"=>"B",.., "26"=>"Z"}
def decode(str, comb='', arr=[])
return arr << s if str.empty?
# Return if the first character of str is not a key of #hd
return arr unless (c = #hd[str[0]])
# Recurse with str less the first char, s with c appended and arr
arr = decode(str[1..-1], s+c, arr)
# If the first two chars of str are a key of #hd (with value c),
# recurse with str less the first two chars, s with c appended and arr
arr = decode(str[2..-1], s+c, arr) if str.size > 1 && (c = #hd[str[0..1]])
arr
end
def num_decode(str) decode(str).size end
decode('1') # => ["A"]
decode('') # => [""].
decode('21') # => ["BA", "U"]
decode('012') # => [""]
decode('102') # => ["JB"]
decode('123') # => ["ABC", "AW", "LC"]
decode('12345') # => ["ABCDE", "AWDE", "LCDE"]
decode('120345') # => ["ATCDE"]
decode('12720132') # => ["ABGTACB", "ABGTMB", "LGTACB", "LGTMB"]
Any more? Yes, I see a hand back there. The gentleman with the red hat wants to see '12121212':
decode('12121212')
# => ["ABABABAB", "ABABABL", "ABABAUB", "ABABLAB", "ABABLL", "ABAUBAB",
"ABAUBL", "ABAUUB", "ABLABAB", "ABLABL", "ABLAUB", "ABLLAB",
"ABLLL", "AUBABAB", "AUBABL", "AUBAUB", "AUBLAB", "AUBLL",
"AUUBAB", "AUUBL", "AUUUB", "LABABAB", "LABABL", "LABAUB",
"LABLAB", "LABLL", "LAUBAB", "LAUBL", "LAUUB", "LLABAB",
"LLABL", "LLAUB", "LLLAB", "LLLL"]
num_decode('1') # => 1
num_decode('21') # => 2
num_decode('12121212') # => 34
num_decode('12912912') # => 8
This looks like a combinatorics problem, but it's also a parsing problem.
(You asked for pointers, so I'm doing this in English rather than dusting off my Ruby.)
I would do something like this:
If X is an empty string, return 1
If X is not a string composed of digits starting with a nonzero digit, return 0
If X contains no 1's or 2's, return 1 (there's only one possible parsing)
If X contains 1's or 2's, it gets a bit more complicated:
Every 1 that is not the last character in X matches both "A" and the first digit of one of the letters "J" through "S".
Every 2 that is not the last character in X and is followed by a digit less than 7 matches both "B" and the first digit of one of the letters.
Count up your 1's and 2's that meet those criteria. Let that number be Y. You have 2^Y combinations of those, so the answer should be 2^Y but you have to subtract 1 for every time you have a 1 and 2 next to each other.
So, if you haven't returned by Step 4 above, count up your 1's that aren't the last character in X, and the 2's that both aren't the last character in X and aren't followed by a 7,8,9, or 10. Let the sum of those counts be called Y.
Now count every instance that those 1's and 2's are neighbors; let that sum be called Z.
The number of possible parsings is (2^Y) - Z.
In the spirit of giving “some pointers”, instead of writing an actually implementation for numDecode let me say that the most logically straightforward way to tackle this problem is with recursion. If the string passed to numDecode is longer than one character then look at the beginning of the string and based on what you see use one or two (or zero) recursive calls to find the correct value.
And the risk of revealing too much, numDecode("1122") should make recursive calls to numDecode("122") and numDecode("22").
# just look for all singles and double as you go down and keep repeating this.. if you get to the end where the string would be 1 or 2 digets long you count 1
# IE
# 121
# 1 that's good 2 that's good 1 that's good if all good then count + 1
# 12 that's good 1 that's good ... no more doubles if all good then count + 1
# 1 that's good 21 that's good if all good then count + 1
# test this on other cases
$str = "2022"
$strlength = $str.length
$count = 0
def decode(str)
if str[0].to_i >= 1 and str[0].to_i <= 9
$count += 1 if str.length == 1
decode(str[1..-1])
end
if str[0..1].to_i >= 10 and str[0..1].to_i <= 26
$count += 1 if str.length == 2
p str.length
decode(str[2..-1])
end
end
decode($str)
p " count is #{$count}"

How do I take the sum of the digits of a square using Ruby?

I'm new to learning Ruby, and I'm trying to ask the user for an input, square that number, and then return the sum of the digits in the squared number. I'm confused when to use .to_s and .to_i, and I'd also like to accomplish this without using a shortcut.
Here's what I have so far (which doesn't work) :
def sqr_digit_sum(n)
square = (n ** 2).to_s
no_of_digits = square.size
sum = 0
i = 0
while i < no_of_digits
sum += square[i].to_i
i += 1
end
puts sum
end
I don't get why if I input 9 for a square of 81, square[0] returns 56 instead of 8. Can someone explain this?
It appears you’re using Ruby 1.8, where String#[] with a Fixnum argument (e.g. '8'[0]) returns the decimal ASCII character value. Which for '8' is 56. Since this is already a Fixnum, calling to_i on it has no effect. You should instead pass an index and length to []:
string = '81'
string[0, 1] #=> "8"
string[1, 1] #=> "1"
If you want all the characters in an array, though, you should use chars/each_char:
string = '81'
string.chars.to_a #=> ["8", "1"]
string.chars.to_a.map { |char| char.to_i } #=> [8, 1]
This makes implementing what you want fairly straightforward using the above and reduce:
n = 9
(n ** 2).to_s.chars.to_a.map { |char| char.to_i }.reduce(0, :+) #=> 9
Ultimately, though, you should upgrade to Ruby 2.0 (or at least 1.9.2+) as soon as possible as 1.8 is no longer supported and receives no security updates.
You could do this
def sqr_digit_sum(n)
square = (n ** 2)
puts square.to_s.split(//).inject(0) { |sum, number_as_string| number_as_string.to_i + sum }
end
Your code works just fine. Also, for the following code, the result is 8 as expected:
n = 9
square = (n ** 2).to_s[0]
puts square
Finally, may I suggest to refactor your code as:
def sqr_digit_sum(n)
sum = 0
(n ** 2).to_s.each_char { |c| sum += c.to_i }
puts sum
end
you don't really need a while loop there.

Ruby Equal to vs Comparison;

I need help for understanding - What is the difference between Equal to and Comparison?
Here is the case
x == y means `Equal to`
x = 10 and y = 10
puts "X and Y are equal" if x == y
puts "X and Y are equal" if x <=> y
I know when and where can I use equal to, but when and where can I use Comparison <=>
Thanks
When you want to compare? It returns -1, 0, 1. For example, sorting users by first name:
users_by_first = users.sort { |u1, u2| u1.fname <=> u2.fname }
Here's another SO question asking about the spaceship operator.
<=> General comparison operator. Returns -1, 0, or +1, depending on whether its receiver is less than, equal to, or greater than its argument.
http://ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html
This is useful for sorting, for one thing.
Equality operators: == and !=
The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.
"koan" == "koan" # Output: => true
The != operator, AKA inequality or bang-tilde, is the opposite of ==. It will return true if both objects are not equal and false if they are equal.
"koan" != "discursive thought" # Output: => true
Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.
When comparing numbers of different types (e.g., integer and float), if their numeric value is the same, == will return true.
2 == 2.0 # Output: => true
Comparison operators
Objects such as numbers and strings, which can be compared (amongst themselves) in terms of being greater or smaller than others, provide the <=> method, also known as the spaceship method. When comparing two objects, <=> returns -1 if the first object is lesser than the second (a < b), 0 in case they are equal (a == b) and 1 when the first object is greater than the second (a > b).
5 <=> 8 # Output: => -1
5 <=> 5 # Output: => 0
8 <=> 5 # Output: => 1
Most comparable or sortable object classes, such as Integer, Float, Time and String, include a mixin called Comparable, which provides the following comparison operators: < (less than), <= (less than or equal), == (equal), > (greater than), >= (greater than or equal). These methods use the spaceship operator under the hood.
Comparison operators can be used in objects of all the above classes, as in the following examples.
# String
"a" < "b" # Output: => true
"a" > "b" # Output: => false
# Symbol
:a < :b # Output: => true
:a > :b # Output: => false
# Fixnum (subclass of Integer)
1 < 2 # Output: => true
2 >= 2 # Output: => true
# Float
1.0 < 2.0 # Output: => true
2.0 >= 2.0 # Output: => true
# Time
Time.local(2016, 5, 28) < Time.local(2016, 5, 29) # Output: => true
When comparing numbers of different classes, comparison operators will implicitly perform simple type conversions.
# Fixnum vs. Float
2 < 3.0 # Output: => true
2.0 > 3 # Output: => false
More info about Ruby operators is available at this blog post.

Resources