Dashing reading out of 2 different CSV's - ruby

Hello everyone I'm currently trying to get my Dashboard working properly, however I cannot figure out a way to get the values into something my List Widget can read.
begin
id = 1
names.each do |item|
label = names[id][0] #names = names.csv path
value = host_status[id]['status'] #host_status = host_status.csv path
items = { label: label, value: value }
id += 1
end
rescue
end
send_event('hosts', { items: items })
So what this script should do is :
write the host_status.csv with the values it gets from the status.cgi (working)
iterate through both the host_status.csv and names.csv getting values from both of them
output should be something like this (label comes from names.csv, value from host_status.csv) =>
{label: "localhost", value: "UP"}, {label: "USV", value: "UP"}
The list widget needs something like an Array in a Hash with the keys label and value as far as I can tell, however my script doesnt return anything is there something like a push method for hashes?

I'm assuming here that names is an array of arrays [['foo'], ['bar']]
and that host_status is an array of objects [{'status' => 'foo'}, {'status' => 'bar'}]
you should just be able to do
names = [['foo'], ['bar']]
host_status = [{'status' => 'foo'}, {'status' => 'bar'}]
labels = names.map(&:first) # ['foo', 'bar']
values = host_status.map {|s| s['status'] } # ['foo', 'bar']
# zip zips together two arrays [['foo', 'foo'], ['bar', 'bar']]
# inject iterates over the array and returns a new data structure
items = labels.zip(values).inject([]) do |memo, (k,v)|
memo.push({label: k, value:v})
memo
end
You should just be able to run that code sample in an irb session.
Enumerable#map:http://www.ruby-doc.org/core-1.9.3/Enumerable.html#method-i-map
Enumerable#zip: http://www.ruby-doc.org/core-1.9.3/Enumerable.html#method-i-zip
Enumerable#inject: http://www.ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject

Related

Next key/value pair overwrites the existing pair in a hash while trying to add pair with new key

I have:
fruits = {
"orange" => {:season => "winter"},
"apple" => {:season => "winter"},
"banana" => {:season => "summer"},
"grape" => {:season => "spring"},
"peach" => {:season => "winter"},
"pineapple" => {:season => "summer"}
}
I want to get:
{
"winter"=>["orange", "apple", "peach"],
"summer"=>["banana", "pineapple"],
"spring"=>["grape"]
}
I did:
def sort_fruits(fruits_hash)
fruits=[]
sorted = {}
seasons = fruits_hash.map {|k, v|v[:season]}
seasons.uniq.each do |season|
fruits.clear
fruits_hash.each do |fruit, season_name|
if season == season_name[:season]
fruits << fruit
end
end
p sorted[season] = fruits ## season changes to new season, so this should have created new key/value pair for new season.
end
sorted
end
I get:
{
"winter"=>["grape"],
"summer"=>["grape"],
"spring"=>["grape"]
}
I couldn't figure out why adding new key/value pair with unique key would overwrite existing pair in a hash. Any help with explanation would be greatly appreciated.
In Ruby mutable objects are passed by reference. It means that when you iterate over seasons in each block this line:
sorted[season] = fruits
saves to sorted[season] a reference to fruits, for every season. After each loop finishes every season has a reference to the same fruits array, which contain items calculated on the last step of the iterator. In your case, it's ["grape"].
Your problem is that you reuse the same fruits array for all the values. Even though you clear it, is is still the same array. If instead of fruits.clear you use fruits = [] then you won't have the issue.
You can see the issue in the following as an example:
arr = ['val']
hash = {
key1: arr,
key2: arr
}
p hash # => { key1: ['val'], key2: ['val'] }
arr.clear
p hash # => { key1: [], key2: [] }
You could alternatively use sorted[season] = fruits.clone or sorted[season] = [*fruits] ... anything that uses a new array.
You have to keep track of when you use 'mutation' methods (those that change objects in-place such as clear) - this is a common pitfall when working with hashes and arrays

How to append values to a key in ruby hashtag

I want to append multiple values to the same key in a ruby hash. Have been using
tags.merge!({'xyz': 'abc'})
to add new tags to the hash, however haven't been able to find a way to add multiple values to the same key.
For example:
tags = {'square': 'blue', 'rectangle': 'green, 'circle': 'yellow'}
I want to add another color to a shape so it looks like:
tags = {'square': 'blue', 'rectangle': 'green, 'circle': ['yellow','red']}
How do I do it?
You can pass a block to merge and do what you want with the values being merged in a duplicated key:
tags = {square: 'blue', rectangle: 'green', circle: 'yellow'}
tags.merge!({ circle: 'red', square: 'red' }) do |key, oldval, newval|
if key == :circle
# Change to array and add the new value
(oldval.is_a?(Array) ? oldval : [oldval]) << newval
else
# Acts like default
newval
end
end
# => {:square=>"red", :rectangle=>"green", :circle=>["yellow", "red"]}
But it will be better if :circle is an array even with one element.
Thanks guys! I went with initializing an empty array for all the tag values and using ternary operator to append values to a specific key like this:
tags.has_key?(:circle) ? (tags[:'circle'] << "#{row['shape']}") : (tags[:'circle'] = ["#{row['shape']}"])
I was using the data from a CSV file so it will write values from a specific row.
And used .uniq to remove duplicates.
You can do something like this:
tags = {'square' => 'blue', 'rectangle' => 'green', 'circle' => 'yellow'}
def add(hash, key, value)
if hash[key]
hash[key] = ([hash[key]] << value).flatten
else
hash[key] = value
end
hash
end
p add(tags, 'circle', 'red')
#=> {"square"=>"blue", "rectangle"=>"green", "circle"=>["yellow", "red"]}
p add(tags, 'circle', 'violet')
#=> {"square"=>"blue", "rectangle"=>"green", "circle"=>["yellow", "red", "violet"]}
Update:
If the value in your hash is going to be an array always, then, something like below can be done
tags[key] = [[tags[key]] << value].flatten.compact

Creating array of hashes in ruby

I want to create an array of hashes in ruby as:
arr[0]
"name": abc
"mobile_num" :9898989898
"email" :abc#xyz.com
arr[1]
"name": xyz
"mobile_num" :9698989898
"email" :abcd#xyz.com
I have seen hash and array documentation. In all I found, I have to do something
like
c = {}
c["name"] = "abc"
c["mobile_num"] = 9898989898
c["email"] = "abc#xyz.com"
arr << c
Iterating as in above statements in loop allows me to fill arr. I actually rowofrows with one row like ["abc",9898989898,"abc#xyz.com"]. Is there any better way to do this?
Assuming what you mean by "rowofrows" is an array of arrays, heres a solution to what I think you're trying to accomplish:
array_of_arrays = [["abc",9898989898,"abc#xyz.com"], ["def",9898989898,"def#xyz.com"]]
array_of_hashes = []
array_of_arrays.each { |record| array_of_hashes << {'name' => record[0], 'number' => record[1].to_i, 'email' => record[2]} }
p array_of_hashes
Will output your array of hashes:
[{"name"=>"abc", "number"=>9898989898, "email"=>"abc#xyz.com"}, {"name"=>"def", "number"=>9898989898, "email"=>"def#xyz.com"}]
you can first define the array as
array = []
then you can define the hashes one by one as following and push them in the array.
hash1 = {:name => "mark" ,:age => 25}
and then do
array.push(hash1)
this will insert the hash into the array . Similarly you can push more hashes to create an array of hashes.
You could also do it directly within the push method like this:
First define your array:
#shopping_list_items = []
And add a new item to your list:
#shopping_list_items.push(description: "Apples", amount: 3)
Which will give you something like this:
=> [{:description=>"Apples", :amount=>3}]

How to get the first key and value pair from a hash table in Ruby

I'm trying to get the first key and value key from a hash table in ruby. I don't know the key values of the hash because it is passed to the method. I cant find anywhere online how to find the first key/value as a separate hash table.
I think hash[0] will just try to find an element with a name 0 it just returns nil when I run the code.
I know I can find the key name and the value and then create a new hash from them but i wonder if there is an easier way to do this so I get a hash right away.
here is my code:
def rps_game_winner(game)
rock_in_hash = game.invert['R']
paper_in_hash = game.invert['P']
scissors_in_hash = game.invert['S']
if(rock_in_hash)
if(paper_in_hash)
return paper_in_hash;
elsif(scissors_in_hash)
return rock_in_hash
end
elsif(paper_in_hash)
if(rock_in_hash)
return paper_in_hash
elsif(scissors_in_hash)
return scissors_in_hash
end
end
key = game.keys[-1]
value = game.values[-1]
winner = {key => value}
return winner
end
game_one = { "Bob" => 'P', "Jim" => 'P' }
puts rps_game_winner(game_one)
This gets me the correct result the problem is I don't understand why it's -1 instead of zero...
And i was hoping there was a better way to get the first key/value pair of a hash table instead of creating new hash table with the key and value you retrieved from the previous table.
You can just do
key, value = hash.first
or if you prefer:
key = hash.keys[0]
value = hash.values[0]
Then maybe:
new_hash = {key => value}
There is a shorter answer that does not require you to use extra variables:
h = { "a" => 100, "b" => 200 , "c" => 300, "d" => 400, "e" => 500}
Hash[*h.first] #=> {"a" => 100}
Or if you want to retrieve a key/value at a any single position
Hash[*h.to_a.at(1)] #=> {"b" => 200}
Or retrieve a key/values from a range of positions:
Hash[h.to_a[1,3]] #=> {"b"=>200, "c"=>300, "d"=>400}
[hash.first].to_h
Another way to do it.
my_hash = { "a" => "first", "b" => "second" }
{ my_hash.keys.first => my_hash.values.first }
This works too

Finding hashes with items from the array using ruby

Sorry for missunderstanding for my fault I didn't check class of item...
I have an array:
array = [link1, link2, link3, link4, etc]
and array_of_hashes with two items: names and links
hash = [ :names, :links ] e.g.
array_of_hashes = [{ :names => name1, :links => link1}, {:names = name2, :links => link2}, ... ]
I want to do something with each pair of items from array_of_hashes which includes links from the array.
UPD: Revised data... sorry for missunderstanding.
It was a bit vague of a question but here is a shot at it.
you will need to reorder what you're trying to access from the hash, unless :name is required.
arr = ["link0", "link1",..."linkN"]
hsh = { "link0", item0, "link1", item1, "link1", item2,..."linkN", itemN}
hsh.each_pair | link, item |
do_something_foo(item) if arr.include?(link) # do_something_foo is a predefined function
end
jagga99 wrote
I want to do something with each item from hash which contain links from the array. Thanks a lot for your help.
If the [:name, :link] is the require pair, then you would need to identify which part is the item to do something with: the name or the link.
Enumerate the array of hashes and search the link array.
array = [:link1, :link2, :link3]
array_of_hashes = [{ :names => :name1, :links => :no_link}, {:names => :name2, :links => :link2}]
array_of_hashes.each do |hash|
if array.any? {|s| s==hash[:links]}
puts "Do something with #{hash[:names].to_s}"
end
end

Resources