Say I have a program with a runtime in the order of weeks with a structure like this:
(1..1000).each do |number|
('a'..'z').each do |letter|
%w(alpha beta omega whatever foo bar).each do |word|
do_long_running_calculation(number,letter,word)
end
end
end
Since the machine running the program may have a sudden unexpected halt, I'd like to save the index that it was on for each array to a file, such that it can re-start from where it left off instead of starting from the beginning in case of a sudden program abort.
Ultimately if this doesn't yet exist as a library (or easy solution that has evaded me), I'm going to make it myself and post it as an answer, but I would like to avoid re-inventing the wheel
Here's a way to deal with your specific example, which could be generalized.
First, two helpers:
class Range
def size # overwrite
case first
when Fixnum
last - first + 1
when String
last.ord - first.ord + 1
end
end
def [](offset)
case first
when Fixnum
first + offset
when String
(first.ord + offset).chr
end
end
end
For example:
(1..10).size #=> 10
('a'..'z').size #=> 26
(1..10)[4] #=> 5
('a'..'z')[4] #=> "e"
For the example:
loops = [(1..1000), ('a'..'z'), %w(alpha beta omega whatever foo bar)]
loop_sizes = loops.map(&:size)
#=> [1000, 26, 6]
prod = 1
tot_nbr_loops, *prod_loop_sizes = (loop_sizes + [1]).reverse.
map { |n| prod = n*prod }.reverse
#=> [156000, 156, 6, 1]
tot_nbr_loops
#=> 156000
prod_loop_sizes
#=> [156, 6, 1]
Using these objects we can create a method that maps a sequence of integers into the triples that are to be enumerated:
def elements(loops, prod_loop_sizes, offset)
loops.zip(prod_loop_sizes).map do |loop, prod|
div, offset = offset.divmod(prod)
loop[div]
end
end
Let's try it:
elements(loops, prod_loop_sizes, 0) #=> [1, "a", "alpha"]
elements(loops, prod_loop_sizes, 5) #=> [1, "a", "bar"]
elements(loops, prod_loop_sizes, 6) #=> [1, "b", "alpha"]
elements(loops, prod_loop_sizes, 155) #=> [1, "z", "bar"]
elements(loops, prod_loop_sizes, 156) #=> [2, "a", "alpha"]
elements(loops, prod_loop_sizes, 156) #=> [2, "a", "alpha"]
elements(loops, prod_loop_sizes, 156) #=> [2, "a", "alpha"]
elements(loops, prod_loop_sizes, 155999) #=> [1000, "z", "bar"]
So now you could write something like this:
save_interval = 10_000
total_number_loops.times do |i|
a,b,c = elements(loops, prod_loop_sizes, i)
# perform calculations with a,b,c
if i % save_interval == 0
<save the value of i and the current state>
<delete the previous saved state>
end
end
One easy way to save to (retrieve from) file most Ruby objects is to use the method Marshal#dump (Marshal#load). (Note the Marshal file format is not guaranteed to remain the same from one Ruby version to the next.)
Ruby provide us the trap method to handle the OS generated SIGNALS. When the system shutdown, then it send the SIGTERM signal. So all we need to handle that signal.
trap("TERM") do
write_data_to_file
end
def write_data_to_file
# code to save data in the file,
end
To read/write from file, cool answer is here:
https://stackoverflow.com/a/4310299/4136098
Related
I'm working on a lab Using a generalized map method to pass an element and block through returning multiple outcomes.
Really struggled on this one. Found some responses but they don't really make sense to me.
Here is the code:
def map(s)
new = []
i = 0
while i < s.length
new.push(yield(s[i]))
i += 1
end
new
end
Here's is the test:
it "returns an array with all values made negative" do
expect(map([1, 2, 3, -9]){|n| n * -1}).to eq([-1, -2, -3, 9])
end
it "returns an array with the original values" do
dune = ["paul", "gurney", "vladimir", "jessica", "chani"]
expect(map(dune){|n| n}).to eq(dune)
end
it "returns an array with the original values multiplied by 2" do
expect(map([1, 2, 3, -9]){|n| n * 2}).to eq([2, 4, 6, -18])
end
it "returns an array with the original values squared" do
expect(map([1, 2, 3, -9]){|n| n * n}).to eq([1, 4, 9, 81])
end
end
I don't get how the above code can give you these 4 different results.
Could someone help me understand it ?
Thank you for your help!
How your method map works
To see how your method operates let's modify your code to add some intermediate variables and some puts statements to show the values of those variables.
def map(s)
new = []
i = 0
n = s.length
puts "s has length #{n}"
while i < n
puts "i = #{i}"
e = s[i]
puts " Yield #{e} to the block"
rv = yield(e)
puts " The block's return value is #{rv}. Push #{rv} onto new"
new.push(rv)
puts " new now equals #{new}"
i += 1
end
puts "We now return the value of new"
new
end
Now let's execute the method with one of the blocks of interest.
s = [1, 2, 3, -9]
map(s) { |n| n * 2 }
#=> [2, 4, 6, -18] (return value of method)
The following is displayed.
s has length 4
i = 0
Yield 1 to the block
The block's return value is 2. Push 2 onto new
new now equals [2]
i = 1
Yield 2 to the block
The block's return value is 4. Push 4 onto new
new now equals [2, 4]
i = 2
Yield 3 to the block
The block's return value is 6. Push 6 onto new
new now equals [2, 4, 6]
i = 3
Yield -9 to the block
The block's return value is -18. Push -18 onto new
new now equals [2, 4, 6, -18]
We now return the value of new
It may by of interest to execute this modified method with different values of s and different blocks.
A replacement for Array#map?
Is this a replacement for Array#map (or Enumerable#map, but for now let's just consider Array#map)? As you defined it at the top level your map is an instance method of the class Object:
Object.instance_methods.include?(:map) #=> true
It must be invoked map([1,2,3]) { |n| ... } whereas Array#map is invoked [1,2,3].map { |n| ... }. Therefore, for your method map to be a replacement for Array#map you need to define it as follows.
class Array
def map
new = []
i = 0
while i < length
new.push(yield(self[i]))
i += 1
end
new
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
Simplify
We can simplify this method as follows.
class Array
def map
new = []
each { |e| new << yield(e) }
new
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
or, better:
class Array
def map
each_with_object([]) { |e,new| new << yield(e) }
end
end
See Enumerable#each_with_object.
Note that while i < length is equivalent to while i < self.length, because self., if omitted, is implicit, and therefore redundant. Similarly, each { |e| new << yield(e) } is equivalent to self.each { |e| new << yield(e) } and each_with_object([]) { ... } is equivalent to self.each_with_object([]) { ... }.
Are we finished?
If we examine the doc Array#map carefully we see that there are two forms of the method. The first is when map takes a block. Our method Array#map mimics that behaviour and that is the only behaviour needed to satisfy the given rspec tests.
There is a second form, however, where map is not given a block, in which case it returns an enumerator. That allows us to chain the method to another. For example (with Ruby's Array#map),
['cat', 'dog', 'pig'].map.with_index do |animal, i|
i.even? ? animal.upcase : animal
end
#=> ["CAT", "dog", "PIG"]
We could modify our Array#map to incorporate this second behaviour as follows.
class Array
def map
if block_given?
each_with_object([]) { |e,new| new << yield(e) }
else
to_enum(:map)
end
end
end
[1, 2, 3, -9].map { |n| n * 2 }
#=> [2, 4, 6, -18]
['cat', 'dog', 'pig'].map.with_index do |animal, i|
i.even? ? animal.upcase : animal
end
#=> ["CAT", "dog", "PIG"]
See Kernel#block_given? and Object#to_enum.
Notes
You might use, say, arr, rather than s as the variable holding the array, as s often denotes a string, just as h typically denotes a hash. One generally avoids names for variables and custom methods that are the names of core Ruby methods. That is also an objection to your use of new as a variable name, as there are many core methods named new.
I have an array a = [1, 2, 3, 4, 5]
If I have an element in the array, I can find the next element in the array via the
a[0].next
Is there a method that I can use to find the previous element
a[1].previous or a[1].before such that the result is
#=> 1
I Googled around a bit and it seems as if most other similar questions involve a loop which I don't want to do. I also checked out the Ruby docs of Enumerator & Enumerable and couldn't seem to find one.
>> a = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
>> a[0].next #=> 2
>> a[2].previous
NoMethodError: undefined method `previous' for 3:Fixnum
from (irb):14
from /Users/Lois/.rvm/rubies/ruby-2.3.1/bin/irb:11:in `<main>'
>> a[2].before
NoMethodError: undefined method `before' for 3:Fixnum
from (irb):15
from /Users/Lois/.rvm/rubies/ruby-2.3.1/bin/irb:11:in `<main>'
Thanks in advance!
If you have an array:
a = [ 1, 2, 3, 4 ]
Then calling a[1] will return the object 2, and there's nothing special about that value, it's without context once you've retrieved it. As such, calling next on it will always yield 3 because that's what Integer#next does.
In order to navigate through that array you need an iterator of some sort, like Enumerator:
e = a.each
Now you can do what you want:
e.next
# => 1
e.next
# => 2
Note that this interface isn't as flexible as you're expecting. You can call next to advance, or rewind to go back to the beginning, but there's no previous. Ruby doesn't have what other languages term as bi-directional iterators, but you might be able to extend this class to add the functions you need if you're feeling brave.
I always end up whipping up something like this.
This approach, of course, isn't limited to Arrays - I didn't want to make it an EnumerableScanner, however, as some enumerations maintain complex state (think of a fibonacci sequence).
class ArrayScanner
attr_reader :index, :array
def initialize(array)
#array = array
#index = 0
end
def next
raise StopIteration unless next?
#array[#index += 1]
end
def peek
raise StopIteration unless next?
#array[#index + 1]
end
def next?
#index + 1 != #array.size
end
def prev
raise StopIteration unless prev?
#array[#index -= 1]
end
def peek_prev
raise StopIteration unless prev?
#array[#index - 1]
end
def prev?
#index - 1 >= 0
end
def eof?
!next?
end
def bof?
!prev?
end
def current
#array[#index]
end
def current=(new_value)
#array[#index] = new_value
end
def size
#array.size
end
def pos
#index
end
def rewind
#index = 0
end
end
a = ArrayScanner.new [1, 2, 3, 4, 5]
a.current #=> 1
a.next #=> 2
a.current #=> 2
a.prev #=> 1
a.prev? #=> false
a.bof? #=> true
4.times { a.next }
a.eof? #=> true
a.current #=> 5
The crystal language has a similar approach, with it's Iterator module.
a = [1, 2, 3, 4, 5]
i = 0
a[i] #=> 1
a[i.next] #=> 2
a[i.pred] #=> 5
i = 1
s = 1
a[i] #=> 2
a[i + s] #=> 3
a[i - s] #=> 1
Let's say I have two enumerators, enum1 and enum2 that must be lazily iterated through (because they have side effects). How do I construct a third enumerator enum3 where enum3.each{|x| x} would lazily return the equivalent of enum1 + enum2?
In my real world use case, I'm streaming in two files, and need to stream out the concatenation.
This seems to work just how I want;
enums.lazy.flat_map{|enum| enum.lazy }
Here's the demonstration. Define these yielding methods with side-effects;
def test_enum
return enum_for __method__ unless block_given?
puts 'hi'
yield 1
puts 'hi again'
yield 2
end
def test_enum2
return enum_for __method__ unless block_given?
puts :a
yield :a
puts :b
yield :b
end
concated_enum = [test_enum, test_enum2].lazy.flat_map{|en| en.lazy }
Then call next on the result, showing that the side effects happen lazily;
[5] pry(main)> concated_enum.next
hi
=> 1
[6] pry(main)> concated_enum.next
hi again
=> 2
Here's some code I wrote for fun awhile back with lazy enumeration thrown in:
def cat(*args)
args = args.to_enum
Enumerator.new do |yielder|
enum = args.next.lazy
loop do
begin
yielder << enum.next
rescue StopIteration
enum = args.next.lazy
end
end
end
end
You would use it like this:
enum1 = [1,2,3]
enum2 = [4,5,6]
enum3 = cat(enum1, enum2)
enum3.each do |n|
puts n
end
# => 1
# 2
# 3
# 4
# 5
# 6
...or just:
cat([1,2,3],[4,5,6]).each {|n| puts n }
Since Ruby 2.6 you can use Enumerable#chain/Enumerator::Chain:
a = [1, 2, 3].lazy
b = [4, 5, 6].lazy
a.chain(b).to_a
# => [1, 2, 3, 4, 5, 6]
Enumerator::Chain.new(a, b).to_a
# => [1, 2, 3, 4, 5, 6]
I'm writing a program that pushes Fibonacci numbers into an array, using Ruby. The code works, but I can't wrap my head around why it works.
This part I understand, it's the Fibonacci equation:
fib_array = []
def fib (n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
This is what I don't understand:
10.times do |x|
fib_array << fib(x)
end
print fib_array
I wrote this grasping at straws, and it works. I don't understand why. I didn't feed it a number to start at, does Ruby take that to mean 0? Also, how did it know to compound the numbers instead of printing [0, 0, 0...]? I apologize if this is a dunderheaded question, but I'm at loss.
It looks like the bottom piece of code simply calls the fib function on x=0, x=1 ... x=9 and stores it's return value at the end of the array. When times is invoked with an iteration variable (x), it begins at 0 and increments on each iteration through the loop. You never fed it a value, however it manages to successfully solve the problem with the iteration variable x being passed in as the parameter to fib.
The second part of your code says:
"From the instance 10 of the class Integer, call the method times with the given block" (The method "recive" a block implicitly).
What is a block? A small piece of code between {braces} or a do-end (like you did).
The method times is called, "iterator". And it will yield 0,1,2,..,9 (in your case). An iterator and the yield statement are always together. Think that yield is like return with memory, when you look for more information.
So, your code could be re-writing like:
10.times { |x| fib_array << fib(x) }
And it will call, the block you pass, on every yield that the method times
does. Calling the method << (append) to the result of fib(x) on your array.
We have:
def fib (n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
which you understand. First let's see what are the first 5 Fibonacci numbers::
fib_array = []
5.times do |x|
fib_array << fib(x)
end
fib_array
#=> [0, 1, 1, 2, 3]
Now let's break this down and see what happening. First look at the docs for the method times. To find them, we need to know what class or module the method is from, because that's how the docs are organized. As 5.class #=> Fixnum, we might look at the docs for Fixnum. Hmmm. times is not there. Evidentally, it was inherited from another class. Let's check:
Fixnum.ancestors
#=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Integer includes Fixnum and BigNum, Numeric includes Integer and Float. (3.14).times doesn't make sense, so it appears times is defined in Integer, and so it is: Integer#times. By defining it there, it is inherited by both Fixnum and Bignum.
Here's a direct way to determine where the method came from:
5.method(:times).owner #=> Integer
It's not important understand this now, but you'll find it handy as you gain experience with Ruby.
OK, the docs say that times return a value if given a block, or an enumerator if not. Let's forget about the block a moment and look at the enumerator that is returned:
enum = 5.times #=> #<Enumerator: 5:times>
The method Enumerator#each passes the elements of the enumerator enum to its block:
do |x|
fib_array << fib(x)
end
assigning them to the block variable x. To see the contents of the enumerator, convert it to an array:
enum.to_a #=> [0, 1, 2, 3, 4]
The result is:
fib_array = []
enum.each do |x|
fib_array << fib(x)
end
fib_array
#=> [0, 1, 1, 2, 3]
which of course is the same result that we obtained previously. Now let's see what's happening step-by-by, by using the method Enumerator#next to extract each element of the enumerator:
x = enum.next #=> 0
fib(x) #=> 0
fib_array << fib(x) #=> [0]
x = enum.next #=> 1
fib(x) #=> 1
fib_array << fib(x) #=> [0, 1]
x = enum.next #=> 2
fib(x) #=> 1
fib_array << fib(x) #=> [0, 1, 1]
x = enum.next #=> 3
fib(x) #=> 2
fib_array << fib(x) #=> [0, 1, 1, 2]
x = enum.next #=> 4
fib(x) #=> 3
fib_array << fib(x) #=> [0, 1, 1, 2, 3]
print fib_array # [0, 1, 1, 2, 3]
That's all there is to it.
I think infinite enumerator is very convenient for writing FP style scripts but I have yet to find a comfortable way to construct such structure in Ruby.
I know I can construct it explicitly:
a = Enumerator.new do |y|
i = 0
loop do
y << i += 1
end
end
a.next #=> 1
a.next #=> 2
a.next #=> 3
...
but that's annoyingly wordy for such a simple structure.
Another approach is sort of a "hack" of using Float::INFINITY:
b = (1..Float::INFINITY).each
b = (1..1.0/0.0).each
These two are probably the least clumsy solution I can give. Although I'd like to know if there are some other more elegant way of constructing infinite enumerators. (By the way, why doesn't Ruby just make inf or infinity as a literal for Float::INFINITY?)
Use #to_enum or #lazy to convert your Range to an Enumerable. For example:
(1..Float::INFINITY).to_enum
(1..Float::INFINITY).lazy
I would personally create my own Ruby class for this.
class NaturalNumbers
def self.each
i = 0
loop { yield i += 1 }
end
end
NaturalNumbers.each do |i|
puts i
end
Ruby 2.7 introduced Enumerator#produce for creating an infinite enumerator from any block, which results in a very elegant, very functional way of implementing the original problem:
irb(main):001:0> NaturalNumbers = Enumerator.produce(0) { |x| x + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbd82d990>:each>
irb(main):002:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):003:0> _
... which - if you're a fan of numbered block parameters (another Ruby 2.7 feature) - can also be written as:
irb(main):006:0> NaturalNumbers = Enumerator.produce(0) { _1 + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbc8b08f0>:each>
irb(main):007:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):008:0> _