Comparing values in two hashes - ruby

I am having trouble in comparing values in two hashes, getting the error "Can't convert String into Integer".
First hash has values captured from a web page using the method "capture_page_data(browser)" and the second hash has data parsed from a report.
Code looks like below:
# Open the web application
# Navigate to a specific page and capture page data
loan_data = Hash.new
loan_data = capture_page_data(browser)
Second hash has values captured from a report generated from the web application.
Code looks like below:
#report_data[page] = Hash.new
# we have written some logic to parse the data from the report into hash variable
Now I am trying to compare the values in theses two hashes to ensure the data in report is matching with the data in application using below code which is giving me the error "Can't convert String into Integer".
loan_data.map{|ld| ld['MainContent_cphContent_LoanOverViewGeneralInfoCtrl_lblRelName']} &
#report_data.map{|rd| rd['Relationship']}
Please help me out in resolving this issue.
Regards,
Veera.

Hash#map iterates through the hash like it was an array of key/value pairs.
{a:1,b:2}.map{|x| puts x.inspect }
# prints
# [:a,1]
# [:b,2]
{a:1,b:2}.map{|k,v| puts "#{k} => #{v}" }
# prints
# a => 1
# b => 2
It applies the block you provide to each pair and collects the results into a new array.
result = {a:1,b:2}.map{|k,v| "#{k} => #{v}" }
puts result.inspect
# prints
# [ "a => 1", "b => 2" ]
I would guess what you are trying to do is compare a single key from each array... in which case...
if loan_data[:id][:span]['MainContent_cphContent_LoanOverViewGeneralInfoCtrl_lblR‌​elName'] == #report_data[1]['Relationship']
log_message("pass")
else
log_message("fail")
end
might be what you are trying to do.. but I am only guessing.
It all depends on the shape of your data.

If you inspect the ld variable inside your block, you will find that it is an array. You can get an element of it with ld[0] or ld[1], but ld[string] does not make sense and results in the exception you are seeing. The ld array will actually be an array with two elements: key and value.

Thanks for your suggestions.. but I found a different solution to compare a single key from two hashes/Arrays using the below code which worked fine.
string_equals?(loan_data[:id][:span]['MainContent_cphContent_LoanOverViewGeneralInfoCtrl_lblRelName'], #report_data[1]['Relationship'] )
Thanks,
Veera.

It's best to debug the content of loan_data and #report_data directly, but you can try .to_sym to convert the key into symbol.
loan_data.map{|ld| ld['MainContent_cphContent_LoanOverViewGeneralInfoCtrl_lblRelName'.to_sym]} &
#report_data.map{|rd| rd['Relationship'.to_sym]}

Related

How to set a variable equivalent to single array object while iterating through array?

Noob question. I need to pass 3,000+ URLs from a CSV sheet to Selenium. I need Selenium to navigate to each one of these links, scrape information and then put that information into a CSV.
The issue I am running into is when I push my CSV URLS into an array, I cannot pass one single object (url) into Selenium at a time.
I know I likely need some sort of loop. I have tried setting up loops and selecting from the array using .map, .select. and just a do loop.
urls.map do |url|
#driver.navigate.to #{url}
name = #driver.find_element(:css, '.sites-embed-
footer>a').attribute('href')
puts name
kb_link = name
kb_array.push(kb_link)
puts 'urls is #{n}'
end
In the above example, Selenium returns an "invalid URL" error message. De-bugging with Pry tells me that my 'url' object is not a single url, but rather still the entire array.
How can I set Selenium to visit each URL from the array one by one?
EDIT: ----------------
So, after extensive de-bugging with Pry, I found a couple issues. First being that my CSV was feeding a nested array to my loop which was causing the URL error. I had to flatten my array and un-nest it to get around that issue.
After that, I had to build a rescue into my loop so that my script didn't die when it encountered a page without the CSS element I was looking for.
Here's the finalized loop.
begin
#urls1.each do |url|
#driver.navigate.to(url)
#driver.manage.timeouts.implicit_wait = 10
name = #driver.find_element(:css, '.sites-embed-
footer>a').attribute('href')
puts name
kb_link = name
kb_array.push(kb_link)
puts 'done'
rescue Selenium::WebDriver::Error::NoSuchElementError
puts 'no google doc'
x = 'no google doc'
kb_array.push(x)
next
end
What about using .each?
Example:
array = [1, 2, 3, 4, 5, 6]
array.each { |x| puts x }
In your code:
urls.each do |url|
#driver.navigate.to #{url}
name = #driver.find_element(:css, '.sites-embed-footer>a').attribute('href')
puts name
kb_link = name
kb_array.push(kb_link)
puts 'urls is #{n}'
end
First of all, it doesn't make much sense to use map if you don't use the result of the block somewhere. map, applied to an Enumerable, returns a new Array, and you don't do anything with the returned array (which in your case would contain just the return values of puts, which is usually nil, so you would get back just an array of nils with the side effect that something is written to stdout.
If you are only interested in the side effects, each or each_with_indexshould be used to traverse an Enumerable. Given the problems you have with map and with each, I wonder what is the actual content of your object urls. Did you ever inspect it? You could do a
p urls
before entering the loop. With 3000 URLs, the output will be huge, but maybe you can run it on a simpler example with less URLs.

Fetching values based on keys from hash

I am using roo gem for reading an xlsx file.
sheet.each(identifier: 'identifier',name: 'name') do |hash|
puts hash.inspect
puts hash['identifier'] => prints empty
end
inspect correctly gives all the hash with all the key/ value pairs
{:identifier=>"3254",:name=>"Ins"}.....so on
I need to fetch the value based on key at every loop. Did something like this puts hash['identifier'] which does not print anything.
How to achieve this.

Store Ruby YAML results into an array

So I have an empty array and a .yml file. I have managed to output the results of that file with this code
puts YAML.load_file('some_yml_file.yml').inspect
I was wondering, how can I pull out each of the data and store them into an empty array?
Is it
emptyarray = []
YAML.load_file('some_yml_file.yml').inspect do |entry|
emptyarray << entry
end
Any help would be appreciated! Thanks!
YAML.load_file returns a Ruby object corresponding to the type of data structure the YAML represents. If the YAML contains a sequence, YAML.load_file will return a Ruby array. You don't need to do anything further to put the data into an array, because it's already an array:
yaml = <<END
---
- I am
- a YAML
- sequence
END
data = YAML.load(yaml)
puts data.class
# => Array
puts data == ["I am", "a YAML", "sequence"]
# => true
(You'll notice that I used YAML.load to load the data from a string rather than a file, but the result is the same as using YAML.load_file on a file with the same contents.)
If the top-level structure in the YAML is not a sequence (e.g. if it's a mapping, analogous to a Ruby hash), then you will have to do additional work to turn it into an array, but we can't tell you what that code would look like without seeing your YAML.
Change YAML.load_file('some_yml_file.yml').inspect do |entry| with YAML.load_file('some_yml_file.yml').each do |entry| and it should work as you expect it (assuming it's not a string).
If you post a sample of your data structure inside the YAML file and what you wish to extract and put in an array then that would help.

Hash Parsing with Ruby

I have the array of hash as shown below:
#line_statuses = [
{:name=>"1", :status=>"online"},
{:name=>"2", :status=>"online"}
]
I'd like to parse each hash inside of #line_statuses array so that I can print out the name and status as shown below.
1: online
2: online
How would I go about doing this?
Technically your #line_statuses variable is an array, so what you have is an array of hashes. In Ruby, to iterate over an array we use the .each method. Then, in each iteration, we can access the values of the hash using the defined keys:
#line_statuses.each do |hash|
puts hash[:name]
puts hash[:status]
end
So simple...:
#line_statuses.each do |line_status|
puts "#{line_status[:name]}: #{line_status[:status]}"
end
try #line_statuses.each{|i| puts i[:name],i[:status]}
Pretty simple:
#line_statuses.each { |line_status| puts "#{line_status[:name]}: #{line_status[:status]}" }

Can't convert String onto integer (TypeError)

Following code return error "Can't convert String onto integer", please help
subject = ['eng','Math','Sci']
grade = ['grade 1','grade 2','grade 3']
subject.each do |sub|
puts ("some string")
grade[sub] .each do |grd|
puts ("some string")
end
end
grade[sub] .each do |grd| thats the problem.
Array elements are accessed by using a index of integer or a range of integers.
You are trying to access a array element by using the variable stored in sub. Since this is a ordinary .each loop it will loop all the elements in the array, in this case 'eng','Math','Sci'. If you want the position of for example 'eng' you could use a .each_with_index
it should probably just be
grade.each do |grd|
with each_with_index it would be
subject.each_with_index do |sub, index|
print sub
print grade[index]
end
If you want a subject -> grade collection it might be good to look into using a Hash like Dave Newton said.
{"eng" => "grade 1","Math" => "grade 2","Sci" => "grade 3"}.each do |subject, grade|
puts "#{subject| #{grade}"
end
When you do
grade[sub] .each do |grd|
Ruby expects sub to be using an integer to reference a position in the list of grades.
subject and grade are both arrays. They can only be accessed by their position. In your each loop, the block gets the actual element (in sub), not the position. So in line 5, you are trying to access grade['eng'], which will not work and produces the error. Note that unlike in e.g. PHP, an array and a hash (an associative array) are different things.
Guessing from your code, you might want to use each_index instead of each which will pass the index number to the block instead of the element.
I'm not sure I understand what you're trying to achieve; however, if you'd like to print subjects and grades and you're sure about the relative order of elements in the arrays, you could do this:
subject = ['eng','Math','Sci']
grade = ['grade 1','grade 2','grade 3']
subject.each_with_index do |sub, idx|
puts "#{sub} - #{grade[idx]}"
end
Output:
eng - grade 1
math - grade 2
sci - grade 3
An hash is however probably more suitable to your needs.

Resources