Iterate into an array of hash - arrays

I'm trying to loop into an array of hash :
response = [
{
"element" => A,
"group" => {"created" => 13, "code" => "Paris.rb", :"rsvp_limit" => 40},
"name" => "CODELAB",
"venue" => {"id" => 17485302, "place" => "la cordée", "visibility" => "public"}
},
{
"element" => B,
"group" => {"created" => 13, "code" => "Paris.rb", :"rsvp_limit" => 40},
"name" => "PARISRB",
"venue" => {"id" => 17485302, "place" => "la cordée", "visibility" => "public"}
}
]
When I run
response[0]["name"], it returns "CODELAB"
response[1]["name"] returns "PARISRB"
How can I make a loop to have the name of each element of this array of hash ?
I tried :
response.each_with_index do |resp, index|
puts array[index]["name"]
end
This is the error I get in my console :
NoMethodError: undefined method `[]' for nil:NilClass
from (pry):58:in `block in __pry__'

The array here seems to be a typo. You meant:
response.each_with_index do |resp, index|
puts resp["name"]
end
The index is not needed because the resp variable is correctly initialized to contain the hash at each iteration.
So it can be simplified to:
response.each do |resp|
puts resp["name"]
end

A little bit shorter:
puts response.map{|hash| hash['name']}
# CODELAB
# PARISRB

Related

For the life of me I can't get this to print the "hobbies" on individual lines?

people = [
{
"first_name" => "Robert",
"last_name" => "Garcia",
"hobbies" => ["basketball", "chess", "phone tag"]
},
{
"first_name" => "Molly",
"last_name" => "Barker",
"hobbies" => ["programming", "reading", "jogging"]
},
{
"first_name" => "Kelly",
"last_name" => "Miller",
"hobbies" => ["cricket", "baking", "stamp collecting"]
}
]
index = 0
while index < "hobbies".length
p people[index]["hobbies"]
index += 1
end

With the class I'm taking they want me to use the p statement not puts and it wants me to run it as a loop I don't understand what the "undefined method '[]'" is can anyone shine some light on this and walk me through it as simply as possible?
You are attempting to iterate through people based on the length of the string "hobbies". Now, that string has length 7, but the people array only has length 3.
You either want:
index = 0
while index < people.length
p people[index]["hobbies"]
index += 1
end
Or better is to just used the each method.
people.each do |person|
p person["hobbies"]
end
When I run this, I see:
irb(main):028:0> people.each do |person|
irb(main):029:1* p person["hobbies"]
irb(main):030:1> end
["basketball", "chess", "phone tag"]
["programming", "reading", "jogging"]
["cricket", "baking", "stamp collecting"]
The reason you get the error you do can be shown with a very simple example:
irb(main):001:0> a = [2]
=> [2]
irb(main):002:0> a.length
=> 1
irb(main):003:0> a[0]
=> 2
irb(main):004:0> a[1]
=> nil
When we access an array at an index that's out of bounds, we don't get an error. We just get nil. In your code, you try to subscript nil and that does cause the error you're seeing.

Building a hash from lines input

Given the lines with a colon as a separator -
1:s11-base:running:/zones/s11-base:3f9d522c:solaris:excl:-:none:<br>
2:s11-template:running:/zones/s11-template:ce57a4db:solaris:excl:-:none:<br>
...
how can I create a hash like
"zoneid" => "1",
"zonename" => "s11-base",
"state" => "running",
next hash
"zoneid" => "2",
"zonename" => "s11-template",
"state" => "running",
and so on.
I want to iterate over all lines, and assign the specific value to the keys from each line.
Anything like this?
input.lines.map do |line|
id, name, state = line.split(":")
{ "zoneid" => id, "zonename" => name, "state" => state }
end
You can use String#split:
str = "1:s11-base:running:/zones/s11-base:3f9d522c:solaris:excl:-:none:<br>"
splitted_str = str.split(":")
# => ["1", "s11-base", "running", "/zones/s11-base", "3f9d522c", "solaris", "excl", "-", "none", "<br>"]
my_hash = {"zoneid": splitted_str[0], "zonename": splitted_str[1], "state" => splitted_str[2]}
# => {:zoneid=>"1", :zonename=>"s11-base", "state"=>"running"}

Ruby pick up a value in hash of array to reformat into a hash

Is there a way I can pick a value in hash of array, and reformat it to be only hash?
Is there any method I can do with it?
Example
[
{
"qset_id" => 1,
"name" => "New1"
},
{
"qset_id" => 2,
"name" => "New2"
}
]
Result
{
1 => {
"name" => "New1"
},
2 => {
"name" => "New2"
}
}
You can basically do arbitary manipulation using reduce function on array or hashes, for example this will get your result
array.reduce({}) do |result, item|
result[item["qset_id"]] = { "name" => item["name"] }
result
end
You can do the same thing with each.with_object do:
array.each.with_object({}) do |item, result|
result[item["qset_id"]] = { "name" => item["name"] }
end
it's basically the same thing but you don't have to make each iteration return the result (called a 'memo object').
You could iterate over the first hash and map it into a second hash:
h1.map{|h| {h['qset_id'] => {'name' => h['name']}} }
# => [{1=>{"name"=>"New1"}}, {2=>{"name"=>"New2"}}]
... but that would return an array. You could pull the elements into a second hash like this:
h2 = {}
h1.each do |h|
h2[h['qset_id']] = {'name' => h['name']}
end
>> h2
=> {1=>{"name"=>"New1"}, 2=>{"name"=>"New2"}}

Hash with array of hashes inside hash

I have a hash like this:
document = {
"results" => {[
{"ip" => 10, "host" => 12},
{"ip" => 13, "host" => 17}
]}
}
It's a one item hash with an array of hashes inside the hash. I specified a value of ip = 10.
If the ip is more than 10, I want to print both keys with values. This hash is very complicated and I don't know how to access these values. Can you help me?
Edit:
What if I had hash like this
document = { "results" => [{"ip" => 10, "host" => 12, "temp" => yes},{"ip" => 13, "host" => 17, "temp" => yes}] } and wanted print only ip and host after matching ip with 10?
document["results"].each do |result|
if result["ip"] > 10
puts result # will print ip and host
end
end
I would use select:
document = { "results" => [{"ip" => 10, "host" => 12},{"ip" => 13, "host" => 17}] }
puts document['results'].select { |hash| hash['ip'] > 10 }
#=> {"ip"=>13, "host"=>17}
Explanation:
document['results']
returns the array of hashes:
[{"ip" => 10, "host" => 12},{"ip" => 13, "host" => 17}]
In the next step select is called on that returned array:
document['results'].select { |hash| hash['ip'] > 10 }
This returns all sub-hashes with an value > 10 assigned to the key 'ip'.
puts just prints the result to STDOUT
I have another problem today. Here is my code:
require 'rubygems'
require 'json'
document = JSON.load File.new("hosts.txt")
file = JSON.load File.new("admins.txt")
first_table = document["results"]
second_table = file["admins"]
new_one = first_table | second_table
First hash looks like this:
document = { "results" => [{"ip" => 10, "host" => 12},{"ip" => 13, "host" => 17}] }
The second hash is
file = { "admins" => [{"host" => 12, "name" => 12},{"host" => 17, "name" => 17}] }
I want merge these two hashes matching them by host by the same value to get
{ "new_one" => [{"ip" => 10, "host" => 12, "name" => 12}, {"ip" => 13, "host" => 17}, "name" => 17]
When I try new_one = first_table | second_tableit says test.rb:24:in <main>': undefined method|' for #Hash:0x00000002ca8be8 (NoMethodError) and when I try new_one = first_table.merge(second_table)its says test.rb:26:in <main>': undefined methodmerge' for #Array:0x00000002ce88b0(NoMethodError). So what is wrong with these hashes? One time they are hashes and the second time they are arrays? How to mach these hashes? The keys and values of host the same in both hashes.

Return Array of Objects/Hashes sorted by attributes

I have an array of objects, in this example represented as hashes:
[
{ "mid" => 123, "updated" => "2015-05-05 05:05:05"}
{ "mid" => 456, "updated" => "2015-05-05 05:06:05"}
{ "mid" => 789, "updated" => "2015-05-05 05:05:05"}
{ "mid" => 123, "updated" => "2015-05-05 05:05:07"}
{ "mid" => 456, "updated" => "2015-05-05 05:05:05"}
]
And I need to get back only elements with the unique mid, in a process of selecting unique objects, timestamp needs to be taken to consideration, where higher datetime is the one to return. So my examples outcome would be:
[
{ "mid" => 456, "updated" => "2015-05-05 05:06:05"}
{ "mid" => 789, "updated" => "2015-05-05 05:05:05"}
{ "mid" => 123, "updated" => "2015-05-05 05:05:07"}
]
I tried couple of different approaches, but I have a problem with my logic, I always get 20 objects back instead of 3. Here is my code:
res = []
queue.length.times do
a = queue.pop
queue.each do |job|
if a.mid == job.mid
if DateTime.parse(a.updated) >= DateTime.parse(a.updated)
res << a
end
else
res << a
end
end
queue << a
end
Any idea?
Assuming you have your input in arr:
arr.group_by do |h|
h['mid'] # group same mids
end.values.map do |all|
all.max_by do |h|
Date.parse h['updated'] # pick latest by date
end
end
#⇒ [
# {"mid"=>123, "updated"=>"2015-05-05 05:05:07"},
# {"mid"=>456, "updated"=>"2015-05-05 05:06:05"},
# {"mid"=>789, "updated"=>"2015-05-05 05:05:05"}
# ]
Please avoid writing phpish code using ruby syntax.
UPD Credits to Cary Swoveland, sort_by+last reduced to max_by.
You can use something like:
queue.sort_by { |r| DateTime.parse(r[:updated]) }.reverse.uniq { |r| r[:mid] }
# => [{:mid=>456, :updated=>"2015-05-05 05:06:05"}, {:mid=>123, :updated=>"2015-05-05 05:05:07"}, {:mid=>789, :updated=>"2015-05-05 05:05:05"}]
where queue is your input array.

Resources