What is the difference between `Range#include?` and `Range#cover?`? - ruby

Edit Fixed following toro2k's comment.
Range#include? and Range#cover? seem to be different as seen in the source code 1, 2, and they are different in efficiency.
t = Time.now
500000.times do
("a".."z").include?("g")
end
puts Time.now - t # => 0.504382493
t = Time.now
500000.times do
("a".."z").cover?("g")
end
puts Time.now - t # => 0.454867868
Looking at the source code, Range#include? seems to be more complex than Range#cover?. Why can't Range#include? be simply an alias of Range#cover? What is their difference?

The two methods are designed to do two slightly different things on purpose. Internally they are implemented very differently too. You can take a look at the sources in the documentation and see that .include? is doing a lot more than .cover?
The .cover? method is related to the Comparable module, and checks whether an item would fit between the end points in a sorted list. It will return true even if the item is not in the set implied by the Range.
The .include? method is related to the Enumerable module, and checks whether an item is actually in the complete set implied by the Range. There is some finessing with numerics - Integer ranges are counted as including all the implied Float values (I'm not sure why).
These examples might help:
('a'..'z').cover?('yellow')
# => true
('a'..'z').include?('yellow')
# => false
('yellaa'..'yellzz').include?('yellow')
=> true
Additionally, if you try
('aaaaaa'..'zzzzzz').include?('yellow')
you should notice it takes a much longer time than
('aaaaaa'..'zzzzzz').cover?('yellow')

The main difference is that include is checking whether object is one of range element, and cover is returning whether object is between edge elements. You can see that:
('a'..'z').include?('cc') #=> false
('a'..'z').cover?('cc') #=> true

date_range = {:start_date => (DateTime.now + 1.days).to_date, :end_date => (DateTime.now + 10.days).to_date}
date_range_to_check_for_coverage = {:start_date => (DateTime.now + 5.days).to_date, :end_date => (DateTime.now + 7.days).to_date}
(date_range[:start_date]..date_range[:end_date]).include?((DateTime.now + 5.days).to_date)
#true
(date_range[:start_date]..date_range[:end_date]).cover?((DateTime.now + 5.days).to_date)
#true
(date_range[:start_date]..date_range[:end_date]).include?(date_range_to_check_for_coverage[:start_date]..date_range_to_check_for_coverage[:end_date])
#true
(date_range[:start_date]..date_range[:end_date]).cover?(date_range_to_check_for_coverage[:start_date]..date_range_to_check_for_coverage[:end_date])
#false
Shouldn't the last line return true ?
The reason I am asking is rubocop flags a conflict when I use include? in place of cover?. And clearly, my logic (to check if the range is included in another range) does not work with cover?.

There's a huge performance difference between cover? and include?: special care when using Date ranges
For the reasons already explained: cover? just checks if your argument is between the begin and the end of the range; in include?, you are checking if your argument is actually inside the range, which involves checking every single element of the range, and not just the begin/end.
Let's run a simple benchmark.
date_range = Date.parse("1990-01-01")..Date.parse("2023-01-01");
target_date = Date.parse("2023-01-01");
iterations = 1000;
Benchmark.bmbm do |bm|
bm.report("using include") { iterations.times { date_range.include?(target_date) } }
bm.report("using cover") { iterations.times { date_range.cover?(target_date) } }
end
Results:
Rehearsal -------------------------------------------------
using include 5.466448 0.071381 5.537829 ( 5.578123)
using cover 0.000272 0.000003 0.000275 ( 0.000279)
---------------------------------------- total: 5.538104sec
user system total real
using include 5.498635 0.046663 5.545298 ( 5.557880)
using cover 0.000284 0.000000 0.000284 ( 0.000280)
As you can see, using #cover? is instantenous; you get your results in 0.000ms.
However, using #include? takes almost 5.5 seconds for the same results.
Choose carefully.

Related

How do I destructure a range in Ruby?

Is it possible to use destructuring in ruby to extract the end and beginning from a range?
module PriceHelper
def price_range_human( range )
"$%s to $%s" % [range.begin, range.end].map(:number_to_currency)
end
end
I know that I can use array coercion as a really bad hack:
first, *center, last = *rng
"$%s to $%s" % [first, last].map(:number_to_currency)
But is there a syntactical way to get begin and end without actually manually creating an array?
min, max = (1..10)
Would have been awesome.
You can use minmax to destructure ranges:
min, max = (1..10).minmax
min # => 1
max # => 10
If you are using Ruby before 2.7, avoid using this on large ranges.
The beginning and end? I'd use:
foo = 1..2
foo.min # => 1
foo.max # => 2
Trying to use destructuring for a range is a bad idea. Imagine the sizes of the array that could be generated then thrown away, wasting CPU time and memory. It's actually a great way to DOS your own code if your range ends with Float::INFINITY.
end is not the same as max: in 1...10, end is 10, but max is 9
That's because start_val ... end_val is equivalent to start_val .. (end_val - 1):
start_value = 1
end_value = 2
foo = start_value...end_value
foo.end # => 2
foo.max # => 1
foo = start_value..(end_value - 1)
foo.end # => 1
foo.max # => 1
max reflects the reality of the values actually used by Ruby when iterating over the range or testing for inclusion in the range.
In my opinion, end should reflect the actual maximum value that will be considered inside the range, not the value used at the end of the definition of the range, but I doubt that'll change otherwise it'd affect existing code.
... is more confusing and leads to increased maintenance problems so its use is not recommended.
No, Until I am proven incorrect by Cary Swoveland, Weekly World News or another tabloid, I'll continue believing without any evidence that the answer is "no"; but it's easy enough to make.
module RangeWithBounds
refine Range do
def bounds
[self.begin, self.end]
end
end
end
module Test
using RangeWithBounds
r = (1..10)
b, e = *r.bounds
puts "#{b}..#{e}"
end
Then again, I'd just write "#{r.begin.number_to_currency}..#{r.end.number_to_currency}" in the first place.
Amadan's answer is fine. you just need to remove the splat (*) when using it since it is not needed
eg,
> "%s to %s" % (1..3).bounds.map{|x| number_to_currency(x)}
=> "$1.00 to $3.00"

What is the purpose of `Array#include?` as compared to `Array#index`?

Array#include? provides only a weaker information than what Array#index provides, i.e., when Array#index returns nil, the corresponding method call with Array#include? will return false, and when Array#index returns an integer, Array#include? returns true. Furthermore, comparing the two indicates that there is no significant difference in speed; rather Array#index often shows a better result than Array#include?:
a = %w[boo zoo foo bar]
t = Time.now
10000.times do
a.include?("foo")
end
puts Time.now - t # => 0.005626235
t = Time.now
10000.times do
a.index("foo")
end
puts Time.now - t # => 0.003683945
Then, what is the purpose of Array#include?? Can't all code using it be rewritten using Array#index?
I know this isn't an official reason, but I can think of a few things:
Clarity: as a name, include? makes more sense at first sight, and also allows easy visual confirmation of code correctness by identifying itself as a boolean predicate. This follows the concept of making wrong code look wrong (see http://www.joelonsoftware.com/articles/Wrong.html)
Good typing: If all you want is a boolean value for a boolean check, making that a number could lead to bugs
Cleanliness: Isn't it nicer to see a printed output of "true" rather than going back to C and having no boolean to speak of?

Ruby for loop a trap?

In a discussion of Ruby loops, Niklas B. recently talked about for loop 'not introducing a new scope', as compared to each loop. I'd like to see some examples of how does one feel this.
O.K., I expand the question: Where else in Ruby do we see what apears do/end block delimiters, but there is actually no scope inside? Anything else apart from for ... do ... end?
O.K., One more expansion of the question, is there a way to write for loop with curly braces { block } ?
Let's illustrate the point by an example:
results = []
(1..3).each do |i|
results << lambda { i }
end
p results.map(&:call) # => [1,2,3]
Cool, this is what was expected. Now check the following:
results = []
for i in 1..3
results << lambda { i }
end
p results.map(&:call) # => [3,3,3]
Huh, what's going on? Believe me, these kinds of bugs are nasty to track down. Python or JS developers will know what I mean :)
That alone is a reason for me to avoid these loops like the plague, although there are more good arguments in favor of this position. As Ben pointed out correctly, using the proper method from Enumerable almost always leads to better code than using plain old, imperative for loops or the fancier Enumerable#each. For instance, the above example could also be concisely written as
lambdas = 1.upto(3).map { |i| lambda { i } }
p lambdas.map(&:call)
I expand the question: Where else in Ruby do we see what apears do/end block delimiters, but there is actually no scope inside? Anything else apart from for ... do ... end?
Every single one of the looping constructs can be used that way:
while true do
#...
end
until false do
# ...
end
On the other hand, we can write every one of these without the do (which is obviously preferrable):
for i in 1..3
end
while true
end
until false
end
One more expansion of the question, is there a way to write for loop with curly braces { block }
No, there is not. Also note that the term "block" has a special meaning in Ruby.
First, I'll explain why you wouldn't want to use for, and then explain why you might.
The main reason you wouldn't want to use for is that it's un-idiomatic. If you use each, you can easily replace that each with a map or a find or an each_with_index without a major change of your code. But there's no for_map or for_find or for_with_index.
Another reason is that if you create a variable within a block within each, and it hasn't been created before-hand, it'll only stay in existance for as long as that loop exists. Getting rid of variables once you have no use for them is a good thing.
Now I'll mention why you might want to use for. each creates a closure for each loop, and if you repeat that loop too many times, that loop can cause performance problems. In https://stackoverflow.com/a/10325493/38765 , I posted that using a while loop rather than a block made it slower.
RUN_COUNT = 10_000_000
FIRST_STRING = "Woooooha"
SECOND_STRING = "Woooooha"
def times_double_equal_sign
RUN_COUNT.times do |i|
FIRST_STRING == SECOND_STRING
end
end
def loop_double_equal_sign
i = 0
while i < RUN_COUNT
FIRST_STRING == SECOND_STRING
i += 1
end
end
times_double_equal_sign consistently took 2.4 seconds, while loop_double_equal_sign was consistently 0.2 to 0.3 seconds faster.
In https://stackoverflow.com/a/6475413/38765 , I found that executing an empty loop took 1.9 seconds, whereas executing an empty block took 5.7 seconds.
Know why you wouldn't want to use for, know why you would want to use for, and only use the latter when you need to. Unless you feel nostalgic for other languages. :)
Well, even blocks are not perfect in Ruby prior to 1.9. They don't always introduce new scope:
i = 0
results = []
(1..3).each do |i|
results << lambda { i }
end
i = 5
p results.map(&:call) # => [5,5,5]

Measure user time or system time in Ruby without Benchmark or time

Since I'm doing some time measurements at the moment, I wondered if it is possible to measure the user time or system time without using the Benchmark class or the command line utility time.
Using the Time class only reveals the wall clock time, not system and user time, however I'm looking for a solution which has the same flexibility, e.g.
time = TimeUtility.now
# some code
user, system, real = TimeUtility.now - time
The reason is that I somehow dislike Benchmark, since it cannot return numbers only (EDIT: I was wrong - it can. See answers below.). Sure, I could parse the output, but that doesn't feels right. The time utility from *NIX systems should solve my problem as well, but I wanted to know if there already is some kind of wrapper implemented in Ruby so I don't need to make these system calls by myself.
Thanks a lot!
I re-read the Benchmark documentation and saw that it has a method named measure. This method does exactly what I want: Measure the time your code needs and returning an object which contains user time, system time, system time of childrens etc. It is as easy as
require 'benchmark'
measurement = Benchmark.measure do
# your code goes here
end
In the process I found out that you can add custom rows to the Benchmark output. You can use this to get the best of both worlds (custom time measurements and a nice output at the end) as follows:
require 'benchmark'
measurements = []
10.times { measurements << Benchmark.measure { 1_000_000.times { a = "1" } } }
# measurements.sum or measurements.inject(0){...} does not work, since the
# array contains Benchmark instances, which cannot be coerced into Fixnum's
# Array#sum will work if you are using Rails
sum = measurements.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
avg = sum / measurements.size
# 7 is the width reserved for the description "sum:" and "avg:"
Benchmark.bm(7, "sum:", "avg:") do |b|
[sum, avg]
end
The result will look like the following:
user system total real
sum: 2.700000 0.000000 2.700000 ( 2.706234)
avg: 0.270000 0.000000 0.270000 ( 0.270623)
You could use the Process::times function, which returns user time/system time. (It does not report wall clock time, you'll need something else for that). Seems to be a bit version or OS dependent though.
This is what it reports on my system (linux, ruby 1.8.7):
$ irb
irb(main):001:0> t = Process.times
=> #<struct Struct::Tms utime=0.01, stime=0.0, cutime=0.0, cstime=0.0>
The docs show this though, so some versions/implementations might only have the first two:
t = Process.times
[ t.utime, t.stime ] #=> [0.0, 0.02]
See times for the underlying call on Linux.
Here's a really crappy wrapper that kind of supports -:
class SysTimes
attr_accessor :user, :system
def initialize
times = Process.times
#user = times.utime
#system = times.stime
end
def -(other)
diff = SysTimes.new
diff.user = #user - other.user
diff.system = #system - other.system
diff
end
end
Should give you ideas to make it work nicely in your context.
This gem might help:
https://github.com/igorkasyanchuk/benchmark_methods
No more code like this:
t = Time.now
user.calculate_report
puts Time.now - t
Now you can do:
benchmark :calculate_report # in class
And just call your method
user.calculate_report

How do I generate a random 10 digit number in ruby?

Additionally, how can I format it as a string padded with zeros?
To generate the number call rand with the result of the expression "10 to the power of 10"
rand(10 ** 10)
To pad the number with zeros you can use the string format operator
'%010d' % rand(10 ** 10)
or the rjust method of string
rand(10 ** 10).to_s.rjust(10,'0')
I would like to contribute probably a simplest solution I know, which is a quite a good trick.
rand.to_s[2..11]
=> "5950281724"
This is a fast way to generate a 10-sized string of digits:
10.times.map{rand(10)}.join # => "3401487670"
The most straightforward answer would probably be
rand(1e9...1e10).to_i
The to_i part is needed because 1e9 and 1e10 are actually floats:
irb(main)> 1e9.class
=> Float
DON'T USE rand.to_s[2..11].to_i
Why? Because here's what you can get:
rand.to_s[2..9] #=> "04890612"
and then:
"04890612".to_i #=> 4890612
Note that:
4890612.to_s.length #=> 7
Which is not what you've expected!
To check that error in your own code, instead of .to_i you may wrap it like this:
Integer(rand.to_s[2..9])
and very soon it will turn out that:
ArgumentError: invalid value for Integer(): "02939053"
So it's always better to stick to .center, but keep in mind that:
rand(9)
sometimes may give you 0.
To prevent that:
rand(1..9)
which will always return something withing 1..9 range.
I'm glad that I had good tests and I hope you will avoid breaking your system.
Random number generation
Use Kernel#rand method:
rand(1_000_000_000..9_999_999_999) # => random 10-digits number
Random string generation
Use times + map + join combination:
10.times.map { rand(0..9) }.join # => random 10-digit string (may start with 0!)
Number to string conversion with padding
Use String#% method:
"%010d" % 123348 # => "0000123348"
Password generation
Use KeePass password generator library, it supports different patterns for generating random password:
KeePass::Password.generate("d{10}") # => random 10-digit string (may start with 0!)
A documentation for KeePass patterns can be found here.
Just because it wasn't mentioned, the Kernel#sprintf method (or it's alias Kernel#format in the Powerpack Library) is generally preferred over the String#% method, as mentioned in the Ruby Community Style Guide.
Of course this is highly debatable, but to provide insight:
The syntax of #quackingduck's answer would be
# considered bad
'%010d' % rand(10**10)
# considered good
sprintf('%010d', rand(10**10))
The nature of this preference is primarily due to the cryptic nature of %. It's not very semantic by itself and without any additional context it can be confused with the % modulo operator.
Examples from the Style Guide:
# bad
'%d %d' % [20, 10]
# => '20 10'
# good
sprintf('%d %d', 20, 10)
# => '20 10'
# good
sprintf('%{first} %{second}', first: 20, second: 10)
# => '20 10'
format('%d %d', 20, 10)
# => '20 10'
# good
format('%{first} %{second}', first: 20, second: 10)
# => '20 10'
To make justice for String#%, I personally really like using operator-like syntaxes instead of commands, the same way you would do your_array << 'foo' over your_array.push('123').
This just illustrates a tendency in the community, what's "best" is up to you.
More info in this blogpost.
I ended up with using Ruby kernel srand
srand.to_s.last(10)
Docs here: Kernel#srand
Here is an expression that will use one fewer method call than quackingduck's example.
'%011d' % rand(1e10)
One caveat, 1e10 is a Float, and Kernel#rand ends up calling to_i on it, so for some higher values you might have some inconsistencies. To be more precise with a literal, you could also do:
'%011d' % rand(10_000_000_000) # Note that underscores are ignored in integer literals
('%010d' % rand(0..9999999999)).to_s
or
"#{'%010d' % rand(0..9999999999)}"
I just want to modify first answer. rand (10**10) may generate 9 digit random no if 0 is in first place. For ensuring 10 exact digit just modify
code = rand(10**10)
while code.to_s.length != 10
code = rand(11**11)
end
Try using the SecureRandom ruby library.
It generates random numbers but the length is not specific.
Go through this link for more information: http://ruby-doc.org/stdlib-2.1.2/libdoc/securerandom/rdoc/SecureRandom.html
Simplest way to generate n digit random number -
Random.new.rand((10**(n - 1))..(10**n))
generate 10 digit number number -
Random.new.rand((10**(10 - 1))..(10**10))
This technique works for any "alphabet"
(1..10).map{"0123456789".chars.to_a.sample}.join
=> "6383411680"
Just use straightforward below.
rand(10 ** 9...10 ** 10)
Just test it on IRB with below.
(1..1000).each { puts rand(10 ** 9...10 ** 10) }
To generate a random, 10-digit string:
# This generates a 10-digit string, where the
# minimum possible value is "0000000000", and the
# maximum possible value is "9999999999"
SecureRandom.random_number(10**10).to_s.rjust(10, '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 = 10,000,000,000
upper_bound = 10**10
# n will be an integer with a minimum possible value of 0,
# and a maximum possible value of 9,999,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 "9999999999" if n == 9_999_999_999
unpadded_str = n.to_s
# Pad the string with leading zeroes if it is less than
# 10 digits long.
# "0" would be padded to "0000000000"
# "123" would be padded to "0000000123"
# "9999999999" would not be padded, and remains unchanged as "9999999999"
padded_str = unpadded_str.rjust(10, '0')
rand(9999999999).to_s.center(10, rand(9).to_s).to_i
is faster than
rand.to_s[2..11].to_i
You can use:
puts Benchmark.measure{(1..1000000).map{rand(9999999999).to_s.center(10, rand(9).to_s).to_i}}
and
puts Benchmark.measure{(1..1000000).map{rand.to_s[2..11].to_i}}
in Rails console to confirm that.
An alternative answer, using the regexp-examples ruby gem:
require 'regexp-examples'
/\d{10}/.random_example # => "0826423747"
There's no need to "pad with zeros" with this approach, since you are immediately generating a String.
This will work even on ruby 1.8.7:
rand(9999999999).to_s.center(10, rand(9).to_s).to_i
A better approach is use Array.new() instead of .times.map. Rubocop recommends it.
Example:
string_size = 9
Array.new(string_size) do
rand(10).to_s
end
Rubucop, TimesMap:
https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Performance/TimesMap
In my case number must be unique in my models, so I added checking block.
module StringUtil
refine String.singleton_class do
def generate_random_digits(size:)
proc = lambda{ rand.to_s[2...(2 + size)] }
if block_given?
loop do
generated = proc.call
break generated if yield(generated) # check generated num meets condition
end
else
proc.call
end
end
end
end
using StringUtil
String.generate_random_digits(3) => "763"
String.generate_random_digits(3) do |num|
User.find_by(code: num).nil?
end => "689"(This is unique in Users code)
I did something like this
x = 10 #Number of digit
(rand(10 ** x) + 10**x).to_s[0..x-1]
Random 10 numbers:
require 'string_pattern'
puts "10:N".gen

Resources