Ruby Put Periodic Progress Messages While Mapping - ruby

I am mapping an array of items, but the collection can be quite large. I would like to put a message to console every so often, to give an indication of progress. Is there a way to do that during the mapping process?
This is my map statement:
famgui = family_items.map{|i|i.getGuid}
I have a def that I use for giving an update when I am doing a for each or while loop.
This is the def:
def doneloop(saymyname, i)
if (i%25000 == 0 )
puts "#{i} #{saymyname}"
end
end
I normally put x = 0 before I start the loop, then x +=1 once I am in the loop and then at the end of my loop, I put saymyname = "specific type items gathered at #{Time.now}"
Then I put doneloop(saymyname, x)
I am not sure how to do that when I am mapping, as there is no loop to construct this around. Does anyone have a method to give updates when using map?
Thanks!

You can map with index:
famgui = family_items.with_index.map {|item, index| item.getGuid; doneloop('sth', index)}

Only the last expression is returned from a map, so you can do something like:
famgui = family_items.with_index.map do |i, idx|
if idx % 100 == 0
puts # extra linefeed
# report every 100th round
puts "items left: #{family_items_size - idx}"
STDOUT.flush
end
current_item += 1
print "."
STDOUT.flush
i.getGuid
end
This will print "." for each item and a status report after every 100 items.
If you want, you can use each_with and populate the array yourself like:
famgui = []
family_items.each_with_index do |i, idx|
famgui << i.getGuid
puts "just did: #{idx} of #{family_items.size}"
end

Related

Why is delete_at not removing elements at supplied index?

I have a Worker and Job example, where each Job has an expensive/slow perform method.
If I have 10 Jobs in my #job_table I'd like to work them off in batches of 5, each within their own process.
After the 5 processes (one batch) have exited I'm trying to remove those Jobs from the #job_table with delete_at.
I'm observing something unexpected in my implementation (see code below) though:
jobs:
[#<Job:0x007fd2230082a8 #id=0>,
#<Job:0x007fd223008280 #id=1>,
#<Job:0x007fd223008258 #id=2>,
#<Job:0x007fd223008208 #id=3>,
#<Job:0x007fd2230081e0 #id=4>,
#<Job:0x007fd2230081b8 #id=5>,
#<Job:0x007fd223008190 #id=6>,
#<Job:0x007fd223008168 #id=7>,
#<Job:0x007fd223008140 #id=8>,
#<Job:0x007fd223008118 #id=9>]
This is the #job_table before the first batch is run. I see that Jobs 0-4 have run and exited successfully (omitted output here).
So I'm calling remove_batch_1 and would expect jobs 0-4 to be removed from the #job_table, but this is what I'm observing instead:
jobs:
[#<Job:0x007fd223008280 #id=1>,
#<Job:0x007fd223008208 #id=3>,
#<Job:0x007fd2230081b8 #id=5>,
#<Job:0x007fd223008168 #id=7>,
#<Job:0x007fd223008118 #id=9>]
I've logged the i parameter in the method and it returns 0-4. But it looks like delete_at is removing other jobs (0,2,4,6,8).
I also wrote another method for removing a batch remove_batch_0 which uses slice! and behaves as expected.
BATCH_SIZE = 5 || ENV['BATCH_SIZE']
class Job
def initialize(id)
#id = id
end
def perform
puts "Job #{#id}> Start!"
sleep 1
puts "Job #{#id}> End!"
end
end
class Worker
def initialize
#job_table = []
fill_job_table
work_job_table
end
def fill_job_table
10.times do |i|
#job_table << Job.new(i)
end
end
def work_job_table
until #job_table.empty?
puts "jobs: "
pp #job_table
work_batch
Process.waitall
remove_batch_1
end
end
def work_batch
i = 0
while (i < #job_table.length && i < BATCH_SIZE)
fork { #job_table[i].perform }
i += 1
end
end
def remove_batch_1
i = 0
while (i < #job_table.length && i < BATCH_SIZE)
#job_table.delete_at(i)
i += 1
end
end
def remove_batch_0
#job_table.slice!(0..BATCH_SIZE-1)
end
end
Worker.new
You use delete_at in a while loop. Let's see what happens:
Image you have an array [0,1,2,3,4,5] and you call:
(1..3).each { |i| array.deleted_at(i) }
In the first iteration you will delete the first element from the array, the array will look like this after this step: [1,2,3,4,5] In the next iteration you will delete the second element, what leads to [1,3,4,5]. Then you delete the third: [1,3,5]
You might want to use Array#shift instead:
def remove_batch_1
#job_table.shift(BATCH_SIZE)
end

Simple Ruby Input Scraper

I'm completely new to ruby and wanted to ask for some help with this ruby script.
it's supposed to take in a string and find out which character occurs the most frequently. It does this using a hash, it stores all the characters in a hash and then iterates through it to find the one with greatest value. As of right now it doesn't seem to be working properly and i'm not sure why. It reads the characters in properly as far as i can tell with print statements. Any help is appreciated.
Thanks!
puts "Enter the string you want to search "
input = gets.chomp
charHash = Hash.new
input.split("").each do |i|
if charHash.has_key?(i)
puts "incrementing"
charHash[i]+=1
else
puts"storing"
charHash.store(i, 1)
end
end
goc = ""
max = 0
charHash.each { |key,value| goc = key if value > max }
puts "The character #{goc} occurs the most frequently"
There are two major issues with you code:
As commented by Holger Just, you have to use += 1 instead of ++
charHash.store(:i, 1) stores the symbol :i, you want to store i
Fixing these results in a working code (I'm using snake_case here):
char_hash = Hash.new
input.split("").each do |i|
if char_hash.has_key?(i)
char_hash[i] += 1
else
char_hash.store(i, 1)
end
end
You can omit the condition by using 0 as your default hash value and you can replace split("").each with each_char:
char_hash = Hash.new(0)
input.each_char do |i|
char_hash[i] += 1
end
Finally, you can pass the hash into the loop using Enumerator#with_object:
char_hash = input.each_char.with_object(Hash.new(0)) { |i, h| h[i] += 1 }
I might be missing something but it seems that instead of
charHash.each { |key,value| goc = key if value > max }
you need something like
charHash.each do |key,value|
if value > max then
max = value
goc = key
end
end
Notice the max = value statement. In your current implementation (i.e. without updating the max variable), every character that appears in the text at least once satisfies the condition and you end up getting the last one.

Ruby Loops While Statements

I have an array of strings dictionary and a string target:
dictionary = ['a', 'b', 'c', 'ab', 'abc']
target = 'abba'
My goal is to return combinations of words from dictionary that can make up target. It should return something like this
['a abc', 'a a b c', 'a ab c']
This is what I have:
def possible_combinations(dictionary, target)
results = [] #eventually an array of results
i = 0 #to go through the dictionary index starting at 0
t = 0 #to go through the target index starting at 0
while i < dictionary.count #while 0 is less than the total index in dict
while t < target.length
if dictionary[i] == target[t]#dict is not changing but target[t] is changing
puts 'I am ' + dictionary[i] + ' at DICT for now'
puts 'I am ' + target[t] + ' at t for now'
puts 'I match somewhere in target so I am added.'#dict[1] is not happening here.
# results.push(dictionary[i])
if results.empty?
results.push(dictionary[i])
puts results
else
results = results[0] + ' ' + dictionary[i] #this is not entirely working?
puts results
end
else
puts 'forget about me'
end
t = t + 1
end
i = i + 1
end
end
and when I run it, I get this:
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a
forget about me
forget about me
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a a
I notice that target[t] is changing, but dictionary[i] is not. I don't understand nested while loops. I think the inner while loop has to finish before it heads to the outer, so dictionary[i] is getting stuck. I want to iterate over i for both dictionary and target, so I am using nested while loops.
If target = 'aaaba', I get this:
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a a
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a a
forget about me
I am a at DICT for now
I am a at t for now
I match somewhere in target so I am added.
a a
Notice how the results got stuck with two 'a' but not three or four?
Instead of using while you can use each on the dictionary and each_char on the target
dictionary.each do |word|
target.each_char do |char|
puts word, char
end
end
The problem w/ your current loops is that you are initializing t = 0 outside both loops, so you only loop through the target once before the inner while condition is always false. If you move that declaration inside the first while loop you will get a result more similar to what you expect
ri Array.each
ri String.index
You're doing this in the most un-ruby like way possible. Read the chapter on the Enumerable module. Look up all the methods String supports. There is almost always a better way than using while in Ruby.
http://ruby-doc.com/docs/ProgrammingRuby/
Note that while String.[1] works Strings are not enumerable, you'd be better off to split the string into an Array of chars if you want to enumerate over it. Or better yet use string search functions rather than direct comparisons. In your
code
dictionary[i] is a string
while
target[i] is a single char.
So you test will never be equal when the dictionary elements are longer than one char.
Here is a more Ruby-like way to write your program:
def possible_combinations(dictionary, target)
results = #eventually an array of results
dictionary.each do |d|
str = ''
target.each do |tl
if d == t #dict is not changing but target[t] is changing
puts 'I am ' + d + ' at DICT for now'
puts 'I am at target ' + t + ' now'
puts 'I match somewhere in target so I am added.' #dict[1] is not happening here.
str = << ' ' unless str.empty?
str << d
puts results
else
puts 'forget about me'
end
end
results << str
end
end
It took just a couple minutes to do this translation. I mainly removed the indices, so the iterations are over elements of the dictionary and target objects.

Loop Controller for ".each do |x|" in ERB

I am trying to style the first element output through an object.each do |x| command by applying an .active class. I cannot figure it out though - how would I do that?
Use each_with_index(). Shown below in a non-ERB example for clarity.
['hello', 'world'].each_with_index do |item, index|
if index == 0
puts "This is the first item"
end
puts item
end
Prints out:
This is the first item
hello
world
It seems very obvious:
objects.first.css_options += ' .active'
And then iterate through all objects in usual manner.
In case of variation can be different, for example you want also apply css option to last element:
objects.zip(['active','','',...]).each do |obj,klass|
obj.css_option += klass
...
end
[obj1, obj2].each_with_index do |item, index|
item.css_option += ' .active' if index == 0
end

Syntax for a for loop in ruby

How do I do this type of for loop in Ruby?
for(int i=0; i<array.length; i++) {
}
array.each do |element|
element.do_stuff
end
or
for element in array do
element.do_stuff
end
If you need index, you can use this:
array.each_with_index do |element,index|
element.do_stuff(index)
end
limit = array.length;
for counter in 0..limit
--- make some actions ---
end
the other way to do that is the following
3.times do |n|
puts n;
end
thats will print 0, 1, 2, so could be used like array iterator also
Think that variant better fit to the author's needs
I keep hitting this as a top link for google "ruby for loop", so I wanted to add a solution for loops where the step wasn't simply '1'. For these cases, you can use the 'step' method that exists on Numerics and Date objects. I think this is a close approximation for a 'for' loop.
start = Date.new(2013,06,30)
stop = Date.new(2011,06,30)
# step back in time over two years, one week at a time
start.step(stop, -7).each do |d|
puts d
end
The equivalence would be
for i in (0...array.size)
end
or
(0...array.size).each do |i|
end
or
i = 0
while i < array.size do
array[i]
i = i + 1 # where you may freely set i to any value
end
array.each_index do |i|
...
end
It's not very Rubyish, but it's the best way to do the for loop from question in Ruby
To iterate a loop a fixed number of times, try:
n.times do
#Something to be done n times
end
If you don't need to access your array, (just a simple for loop) you can use upto or each :
Upto:
2.upto(4) {|i| puts i}
2
3
4
Each:
(2..4).each {|i| puts i}
2
3
4
What? From 2010 and nobody mentioned Ruby has a fine for /in loop (it's just nobody uses it):
ar = [1,2,3,4,5,6]
for item in ar
puts item
end
['foo', 'bar', 'baz'].each_with_index {|j, i| puts "#{i} #{j}"}
Ruby's enumeration loop syntax is different:
collection.each do |item|
...
end
This reads as "a call to the 'each' method of the array object instance 'collection' that takes block with 'blockargument' as argument". The block syntax in Ruby is 'do ... end' or '{ ... }' for single line statements.
The block argument '|item|' is optional but if provided, the first argument automatically represents the looped enumerated item.

Resources