Print out elements in a hash table, Ruby - ruby

I have a hash table that looks like this:
hash =
"{\"url\":\"/system/message\",\"device\":\"UNKNOWN\",\"version\":\"1.0\",\"timestamp\":\"2018-08-28T11:16:29.516617Z\",\"object\":{\"timestamp\":\"2018-08-28T11:16:29.516490Z\",\"id\":9800,\"debug_level\":2,\"message\":\"Got new port configuration\"}}"
hash.each do |variable|
puts variable
end
This do not work

You'll need to first convert your string to a hash.
require 'json'
my_hash = JSON.parse(hash)
my_hash.each do |key, value|
puts value
end

You can also do the following:
require 'json'
values = JSON.parse(hash).map {|k,v| puts v }

Related

What is an elegant Ruby way to have a condition of 'nil'?

Is there a more elegant way to write this code?
def create_a_hash_from_a_collection
my_hash = {}
collection_of_hashes.each do |key, value|
my_hash[key] = {} if my_hash[key].nil?
my_hash[key] = value
end
my_hash
end
The line that seems clumsy to me is this:
my_hash[key] = {} if my_hash[key].nil?
Is there a shorthand way of expressing it?
If you want to have a brand new hash for each key in your initial hash you need to initialise it with a block:
hash = Hash.new { |hash, key| hash[key] = {} }
hash[:foo].object_id == hash[:bar].object_id #=> false
Otherwise, if you do this, It will be always the same default hash
hash = Hash.new({})
hash[:foo].object_id == hash[:bar].object_id #=> true
You can use ||= operator which does exactly what you want
my_hash[key] ||= {}
The rest of my answer here is because I'm not sure what a "collection of hashes" is, so my best guess is that it would be an array of hashes. If I'm wrong, let me know and disregard the rest of this answer.
It seems that the rest of your method may not do what it sounds like you're trying to do. Consider:
#collection_of_hashes = [{foo: 'bar'}, {baz: 'qux'}]
def create_a_hash_from_a_collection
my_hash = {}
#collection_of_hashes.each do |key, value|
# this is not actually doing anything here and returns same with or
# without the following line
# my_hash[key] ||= {}
my_hash[key] = value
end
my_hash
end
#=> {{:foo=>"bar"}=>nil, {:baz=>"qux"}=>nil}
But what you probably want is
def create_a_hash_from_a_collection
my_hash = {}
#collection_of_hashes.each do |hash|
hash.keys.each do |k|
my_hash[k] = hash[k]
end
end
my_hash
end
#=> {:foo=>"bar", :baz=>"qux"}
But also keep in mind, if any of your "collection of hashes" which we would tend to assume would be an array of hashes, contain the same key, which one wins? This code, it would be the last item in the array's key value. What is the actual goal of your method?
I guess what you want is to initialise your my_hash with a default value, so then you don't need to check if it's nil or not.
That can be done using the Hash.new constructor, compare:
my_hash = {}
puts my_hash['no_existing_key'] #=> nil
my_hash = Hash.new({})
puts my_hash['no_existing_key'] #=> {}
You then can reduce your code to:
def create_a_hash_from_a_collection
my_hash = Hash.new({})
collection_of_hashes.each do |key, value|
my_hash[key] = value
end
my_hash
end
Since you are assigning value anyway, maybe you could use my_hash[key] = value || {}?
So, if value to assign is nil, the value of that key becomes {}.

Put every Hash Element inside of an Array Ruby

Let's say I have a Hash like this:
my_hash = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}
And I want to convert every element inside the hash that is also a hash to be placed inside of an Array.
For example, I want the finished Hash to look like this:
{"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}
Here is what I've tried so far, but I need it to work recursively and I'm not quite sure how to make that work:
my_hash.each do |k,v|
if v.class == Hash
my_hash[k] = [] << v
end
end
=> {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>{"c2"=>"c3"}}]}
You need to wrap your code into a method and call it recursively.
my_hash = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}
def process(hash)
hash.each do |k,v|
if v.class == Hash
hash[k] = [] << process(v)
end
end
end
p process(my_hash)
#=> {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}
Recurring proc is another way around:
h = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}
h.map(&(p = proc{|k,v| {k => v.is_a?(Hash) ? [p[*v]] : v}}))
.reduce({}, &:merge)
# => {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}
It can be done with single reduce, but that way things get even more obfuscated.

Editing yaml hashmap with ruby and rake

I have a yaml who's elements need to be filled by a user... sounds simple enough. I am attempting to read the file, print the keys, ask for a value, and store the updated file.
cnfg.yml:
thing:
something:
another_thing:
much_depth:
such_yml:
...
Here is my code thus far:
task :setup_cnfg do
config = YAML.load_file 'cnfg.yml'
config.each do |key, value|
puts key
value.each do |k, v|
print " #{k}: "
v = STDIN.gets.chomp() #STDIN is there due to some strange rake shenanigans
end
end
File.open('cnfg.yml','w') {|f| f.write config.to_yaml}
end
If I print 'v' after I capture the input it does show the intended value but if i print the hash afterwords all imputed values will be gone!
What would I do in order to correctly populate and store all of my data fields?
You should actually assign the new v back to the value hash:
task :setup_cnfg do
config = YAML.load_file 'cnfg.yml'
config.each do |key, value|
puts key
value.each do |k, _|
print " #{k}: "
value[k] = STDIN.gets.chomp()
end
end
File.open('cnfg.yml','w') {|f| f.write config.to_yaml}
end

Ruby: how to iterate over an array of hash items?

irb> pp config
[{"file"=>"/var/tmp"},
{"size"=>"1024"},
{"modified"=>"03/28/2012"}]
=> nil
In the code,
config.each do |d|
# then how to break d into (k, v)???
end
config.each do |items|
items.each do |key, value|
# e.g. key="file", value="/var/tmp", etc.
end
end
Just do
config.each do |hash|
(k,v),_ = *hash
end
Inspired by #Arup's answer, here's a solution that doesn't require a extra, unused variable in the parallel assignment:
config.each do |hash|
key, value = hash.to_a[0]
end
to_a converts the hash into the same kind of array that you would get by using splat *hash, but you can actually index the first element of the array (i.e. the first key/value pair) with [0] this way, while trying to do so with splat (*hash) generates a syntax error (at least in Ruby version 2.1.1):
>> k,v = (*hash)[0]
SyntaxError: (irb):4: syntax error, unexpected ')', expecting '='
k,v = (*x)[0]
^
from c:/RailsInstaller/Ruby1.9.3/bin/irb:12:in `<main>'
>>
Of course, depending on what you're going to do with the key and value variables, it might make your code shorter and more readable to use one of these standard block constructs:
config.each do |hash|
hash.each { |key,value| puts "#{key}: #{value}" }
end
# or
config.each do |hash|
hash.each do |key,value|
puts "#{key}: #{value}"
end
end

How to get the key of a hash

Right now I have a double hash called data like the following:
data [name][action]
ie
data = {"Mike" => {"Walked" => 13, "Ran" => 5}, "Steve" => {...}}
For this particular hash, I don't actually know the keys in the hash, I just want to iterate over it, like so:
data.each |item| do
#how to get the key name for item here?
puts item["Walked"].to_s
puts item["Ran"].to_s
end
I'd like to get the key so I can display it in a table beside the values.
You can iterate over a hash using:
data.each do |key, value|
end
You can use each with a key, value syntax, as described in the each documentation:
data.each do |key, values|
puts key.to_s
values.each do |value|
value.to_s
end
end
You could also use keys or values depending on what you wanted to achieve.
data.keys.each do |key|
puts key #lists all keys
end
data.values.each do |value|
puts value #lists all values
end
data.keys.first #first key
and so on.

Resources