Fetching values based on keys from hash - ruby

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.

Related

How to access Sequel result with dot operator in ruby?

I am newbie to Sequel and ruby and I have one thing need your help.
In a word, I can't access database query result with dot operator.
I am using sequel adapter in padrino ruby project.
For example,
persons = Person.all
persons.each do |p|
puts p.name . # this output correct person name, as 'john'
end
But if I do some query
persons = Person.where(:age=>20)
persons.each do |p|
puts p.name . # this line cause error
end
I compared their data types and there are different each other.
puts persons # in first case - array
#<Gig:0x007fbdb6d64ef0>
#<Gig:0x007fbdb6d64838>
#<Gig:0x007fbdb6d641f8>
puts persons # in second case - object
#<Sequel::Postgres::Dataset:0x007fbdbc614898>
So I tried to change result to hash array in second case to access fields with dot operator
persons_hash= persons.collect do |p|
ro.to_hash
end
In this case, I was able to access user name with person[0][:name], but I couldn't access with dot operator.
So I want to know how should I have to do to access Sequel query result using dot operator.
Thanks :)
persons.each do |p|
puts p.name . # this line cause error
end
What exact error are you getting here? I'm guessing an undefined method error? Seems you may be familiar with ActiveRecord syntax. I have not used sequel myself, but it is a bit different from AR. According to their docs, you would do something like this
persons.map(:name) # => ['Harry', 'Steve', 'Israel', ...]
The all method returns an array of hashes, where each hash corresponds to a record.
For your above example, I would try the following:
persons.each do |p|
puts p[:name] . # here we are now accessing the name hash key instead of trying to access the name method.
end
You want to access the name key of each hash being iterated over. Because you are iterating through an array OF hashes. This is why you could access that data with person[0][:name]. You were calling the 0th item of the persona array and accessing its 'name' hash key.

How to save a hash in a file and use it later in ruby?

So i got in big troubles with this exam at university because i am stuck with a part in my ruby code. I just can't figure out how
" If the user presses 2 the program shall ask for an employee number and afterwards search for the employee. If the program finds it, then print and if not, print a message saying it doesn’t have it."
My problem is that i'm not sure that the information is saved corectly in the file. But if it is... the problem is that the hash i've made isn't taking the information that already is saved in the file and only works with the information it has received last.
puts "Insert Registration number \n"
search = gets.chomp
hash = Hash.new()
hash = {(regnr) => (name)}
hash.each do |key, value|
puts "#{key} \t | \t #{value}"
end
search =~ File.new("employees.txt", "r")
if hash.has_key? (search)
print "The person you were looking for is "
puts hash [search]
else
puts "He isn't one of our employees"
end
I have to tell you guys that i have only been coding for one month and the school isn't taking me easy...
I'd recommend using yaml. Take a look around the web for some examples on using YAML. It's a structured markup that can represent hashes. You can easily dump and load simple ruby objects like hashes and arrays.
require 'yaml'
parsed = begin
employee_hash = YAML.load(File.open("employees.yml"))
rescue ArgumentError => e
puts "Could not parse YAML: #{e.message}"
end

In Ruby, group_by where I know there's only 1 element per group

I have a CSV file where one column is a primary key. When I do this:
CSV.read(ARGV[0], headers: true).group_by {|r| r['myKey']}
I get a hash table from key to a list of rows, where the list is always length 1.
Is there a version of group_by which asserts that there's only a single value per key, and creates a hash from key to that single value?
Failing that, is there something like .first which asserts that there's exactly one element in the array/enumerable? I like my scripts to fail when my assumptions are wrong, rather than silently return the wrong thing.
If you use Rails you can use index_by method.
If you know the values r['myKey'] are unique, there's no point in using group_by. As I understand the question, you could do this:
rows = CSV.read(ARGV[0], headers: true)
Hash[rows.map { |r| r['myKey'] }.zip(rows)]
In Ruby 2.0+ the second row could be written:
rows.map { |r| r['myKey'] }.zip(rows).to_h
No. I don't believe there is. But you can solve your problem with each_with_object like so:
CSV.
read(ARGV[0], headers: true).
each_with_object({}) do |r, hash|
key = r['myKey']
value = r
hash[key] = value
end
It's a shame Ruby doesn't have this. Here's what I decided to go on, based on Humza's answer:
module Enumerable
def group_by_uniq
each_with_object({}) do |value, hash|
key = yield value
raise "Multiple values for key \"{key}\"!" unless ! hash.key?(key)
hash[key] = value
end
end
end
If you use your code in you first example you can run this code to check that all hashes are of length 1:
raise 'multiple entries per key!' unless my_hash.values.any?{|val| val.size!=1}
IF you can get the keys into an array you can check that they do not iclude duplicates by:
raise 'multiple entries per key!' unless my_keys.uniq.size == my_keys.size

Comparing values in two hashes

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]}

Import json data into redis

i'm new to redis and ruby i'm using the following code
response = HTTParty.get('posts.json')
json = JSON(response.body)
json.each do |item|
puts item
puts json[item]
puts item['content']
redis.hset 'latest_posts', item, item['title']
end
puts json[item]
returns the following error no implicit conversion of Hash into Integer
inside each loop i want to output the keys for example id, title, content with puts item (now returns the whole object) and with json[item] data in keys any help? if i try for example
%w{id title content}.each do |key|
puts key
puts json[key]
end
again no implicit conversion of String into Integer
From your code it seems that you expect an array of hashes in your JSON.
I see two problems here:
1.
puts json[item]
puts item['content']
an item is a hash. json[item] makes no sense to me.
2.
redis.hset 'latest_posts', item, item['title']
is supposed to set a key item in the Redis hash 'latest_posts' to the value item['title']. But item is a hash, and, I think, Redis expects a string as the filed name.
BTW, is not it JSON.parse response.body?

Resources