how i use the number 05798300 exact in ruby?
When i enter:
2.0.0p247 :031 > 05798300
SyntaxError: (irb):31: Invalid octal digit
or
2.0.0p247 :001 > 04704110
=> 1280072
I need check if the number: 04704110 is between 0100000000 and 09000000.
If you need to keep leading zeros, store your postal codes as strings and you can compare them as such:
test = '04704110'
lower = '01000000' #assuming eight digits
upper = '09000000'
p lower < test && test < upper
#=> true
Otherwise, compare them as integers but format them when you print them, adding leading zeros:
test = 4704110
p "%08d" % test
#=> "04704110"
Related
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.
In console:
1.9.3p547 :010 > my_s = 00013.to_s
=> "11"
1.9.3p547 :011 > my_s = 00013.to_i
=> 11
1.9.3p547 :012 > 13.to_s
=> "13"
1.9.3p547 :013 > 13.to_i
=> 13
Why this difference in treatment? How can comparisons be made between string values that are fundamentally numbers but that have been padded with zeros?
You wrote 00013, with leading zeros. In Ruby (and a lot of other languages), integer literals starting with zeros are treated as octal (base 8), so the number you typed (when written in decimal) is really 8 + 3 = 11.
To answer the second part of your question: If you have a string like '00013', you can just call #to_i on it and Ruby will actually convert it to 13 (in decimal). So that should allow you to make comparisons.
In Ruby's Integer class, leading zeroes are not stored.
Leading zeroes are number literals and are interpreted like so
Octal: 0, 0o
Hexadecimal: 0, 0x
Binary: 0b
Decimal: 0d
'00013' has three leading zeroes, and matches the format 0o. IRB treats these numbers as octal(base 8)
You don't have any "string values that are fundamentally numbers but that have been padded with zeros" in your example. If you did, it would actually work how you expect:
"00013".to_i
# => 13
You have a number literal in your example that has been padded with zeroes. As the other answers say, this is treated as an octal representation by ruby.
But if you actually had a string representation of a number, padded with zeroes, it works fine, just call #to_i on it.
I have a number, and would like to see if I multiply the number by a real number, if the new number has the exact same digits as the previous number, only re-arranged. For example, if I wanted to multiply a number by 2 and see if the digits remained the same, I would do
125874
=> 251748
251748 is 125874 multiplied by 2 and both numbers have the exact same digits, only re-arranged. For simplicity, I'm only testing it with multiples of 2 for now. This is what I tried to do and failed.
x = 125874
array = x.to_s.chars.map{|x|x.to_i}
=> [1,2,5,8,7,4]
array.permutation.include?((x * 2).to_s.chars.map{|x|x.to_i}
=> true
Now, I tried to run this in a loop to find all numbers under 100,000 that met this criteria.
range = (1..100000).to_a
range.select do |x|
array = x.to_s.chars.map{|x|x.to_i}
array.permutation.include?((x * 2).to_s.chars.map{|x|x.to_i}
end
=> []
Now, it should have recorded at least 125874 in that array, since 125874 * 2 equals 251748, which is a permutation of 125874.
I think I managed to out-confuse myself on this one.
First assume that if the given number contains repeated digits, we require that the number and product of the number and a multiplier contain the same number of each digit that appears in either number:
def same_digits?(nbr, mult)
nbr.to_s.chars.sort == (nbr * mult).to_s.chars.sort
end
same_digits?(125874,2) #=> true (125874*2 => 251748)
same_digits?(125874,3) #=> false (125874*3 => 377622)
If nbr and nbr*prod must contain the same digits, but not necessarily the same number of each of those digits, the method differs only slightly:
def same_digits?(nbr, mult)
nbr.to_s.chars.uniq.sort == (nbr * mult).to_s.chars.uniq.sort
end
same_digits?(10255,2) #=> true (10255*2 => 20510)
same_digits?(10255,3) #=> false (10255*3 => 30765)
In this second case there are many other ways to determine if two arrays contain the same elements after duplicates have been removed. Let:
a = nbr.to_s.chars.uniq
b = (nbr*mult).to_s.chars.uniq
Above I've used a.sort == b.sort to check for a match. Here are a few of other ways:
(a&b)==a && (a&b)==b # Array intersection
(a-b).empty? && (b-a).empty? # Array difference
require 'set'
a.to_set == b.to_set
'10:' < '1:'
# => true
Can someone explain me why the result in the above example is true? If I just compare '1:' and '2:' I get the result expected:
'1:' < '2:'
# => true
Strings are compared character by character.
When you compare 1: vs 2:, the comparison begins with 2 vs 1, and the comparison stops there with the expected result.
When you compare 1: vs 10:, the comparison begins with 1 vs 1, and since it is a tie, the comparison moves on to the next comparison, which is : vs 0, and the comparison stops there with the result that you have found surprising (given your expectation that the integers within the strings would be compared).
To do the comparison you expect, use to_i to convert both operands to integers.
It is character by character comparison in ASCII.
'10:' < '1:' is (49 < 49) || (48 < 58) || (58 < ?)
#=> true
'1:' < '2:' is (49 < 50) || (58 < 58)
#=> true
Left to Right boolean check is used and check breaks where true is found.
Note: It is just my observation over various example patterns.
The first character of each of your two strings are the same. And as Dave said in the comments, the second character of the first, '0', is less than ':', so the first string is less than the second.
Because the ASCII code for 0 is 48, which is smaller than the ASCII code for :, which is 58.
For some reason, I'm getting unexpected results in the range comparisons of unicode characters.
To summarize, in my minimized test code, ("\u1000".."\u1200") === "\u1100" is false, where I would expect it to be true -- while the same test against "\u1001" is true as expected. I find this utterly incomprehensible. The results of the < operator are also interesting -- they contradict ===.
The following code is a good minimal illustration:
# encoding: utf-8
require 'pp'
a = "\u1000"
b = "\u1200"
r = (a..b)
x = "\u1001"
y = "\u1100"
pp a, b, r, x, y
puts "a < x = #{a < x}"
puts "b > x = #{b > x}"
puts "a < y = #{a < y}"
puts "b > y = #{b > y}"
puts "r === x = #{r === x}"
puts "r === y = #{r === y}"
I would naively expect that both of the === operations would produce "true" here. However, the actual output of running this program is:
ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.3.0]
"\u1000"
"\u1200"
"\u1000".."\u1200"
"\u1001"
"\u1100"
a < x = true
b > x = true
a < y = true
b > y = true
r === x = true
r === y = false
Could someone enlighten me?
(Note I'm on 1.9.3 on Mac OS X, and I'm explicitly setting the encoding to utf-8.)
ACTION:
I've submitted this behavior as bug #6258 to ruby-lang.
There's something odd about the collation order in that range of characters
irb(main):081:0> r.to_a.last.ord.to_s(16)
=> "1036"
irb(main):082:0> r.to_a.last.succ.ord.to_s(16)
=> "1000"
irb(main):083:0> r.min.ord.to_s(16)
=> "1000"
irb(main):084:0> r.max.ord.to_s(16)
=> "1200"
The min and max for the range are the expected values from your input, but if we turn the range into an array, the last element is "\u1036" and it's successor is "\u1000". Under the covers, Range#=== must be enumerating the String#succ sequence rather than simple bound checking on min and max.
If we look at the source (click toggle) for Range#=== we see it dispatches to Range#include?. Range#include? source shows special handling for strings -- if answer can be determined by string length alone, or all the invloved strings are ASCII, we get simple bounds checks, otherwise we dispatch to super, which means the #include? gets answered by Enumerable#include? which enumerates using Range#each which again has special handling for string and dispatches to String#upto which enumerates with String#succ.
String#succ has a bunch of special handling when the string contains is_alpha or is_digit numbers (which should not be true for U+1036), otherwise it increments the final char using enc_succ_char. At this point I lose the trail, but presumably this calculates a successor using the encoding and collation information associated with the string.
BTW, as a work around, you could use a range of integer ordinals and test against ordinals if you only care about single chars. eg:
r = (a.ord..b.ord)
r === x.ord
r === y.ord
Looks like Range doesn't mean what we think it means.
What I think is happening is that you're creating is a Range that is trying to include letters, digits, and punctuation. Ruby is unable to do this and is not "understanding" that you want essentially an array of code points.
This is causing the Range#to_a method to fall apart:
("\u1000".."\u1099").to_a.size #=> 55
("\u1100".."\u1199").to_a.size #=> 154
("\u1200".."\u1299").to_a.size #=> 73
The zinger is when you put all three together:
("\u1000".."\u1299").to_a.size #=> 55
Ruby 1.8.7 works as expected-- as Matt points out in the comments, "\u1000" is just the literal "u1000" because no Unicode.
The string#succ C source code doesn't just return the next codepooint:
Returns the successor to <i>str</i>. The successor is calculated by
incrementing characters starting from the rightmost alphanumeric (or
the rightmost character if there are no alphanumerics) in the
string. Incrementing a digit always results in another digit, and
incrementing a letter results in another letter of the same case.
Incrementing nonalphanumerics uses the underlying character set's
collating sequence.
Range is doing something different than just next, next, next.
Range with these characters does ACSII sequence:
('8'..'A').to_a
=> ["8", "9", ":", ";", "<", "=", ">", "?", "#", "A"]
But using #succ is totally different:
'8'.succ
=> '9'
'9'.succ
=> '10' # if we were in a Range.to_a, this would be ":"