Mapping to the Keys of a Hash - ruby-on-rails

I am working with a hash called my_hash :
{"2011-02-01 00:00:00+00"=>816, "2011-01-01 00:00:00+00"=>58, "2011-03-01 00:00:00+00"=>241}
First, I try to parse all the keys, in my_hash (which are times).
my_hash.keys.sort.each do |key|
parsed_keys << Date.parse(key).to_s
end
Which gives me this :
["2011-01-01", "2011-02-01", "2011-03-01"]
Then, I try to map parsed_keys back to the keys of my_hash :
Hash[my_hash.map {|k,v| [parsed_keys[k], v]}]
But that returns the following error :
TypeError: can't convert String into Integer
How can I map parsed_keys back to the keys of my_hash ?
My aim is to get rid of the "00:00:00+00" at end of all the keys.

Why don't you just do this?
my_hash.map{|k,v| {k.gsub(" 00:00:00+00","") => v}}.reduce(:merge)
This gives you
{"2011-02-01"=>816, "2011-01-01"=>58, "2011-03-01"=>241}

There is a new "Rails way" methods for this task :)
http://api.rubyonrails.org/classes/Hash.html#method-i-transform_keys

Using iblue answer, you could use a regexp to handle this situation, for example:
pattern = /00:00:00(\+00)+/
my_hash.map{|k,v| {k.gsub(pattern,"") => v}}.reduce(:merge)
You could improve the pattern to handle different situations.
Hope it helps.
Edit:
Sorry, iblue have already posted the answer

Another alternative could be:
map
return converted two elements array [converted_key, converted_value]
convert back to a hash
irb(main):001:0> {a: 1, b: 2}.map{|k,v| [k.to_s, v.to_s]}.to_h
=> {"a"=>"1", "b"=>"2"}

Related

Generation of table and accessing elements of a Array of Hashes

I have the following Array of hashes in a rails application:
a = ["{\"ROW1\"=>{\"correct\"=>{\"h\"=>\"10\", \"m\"=>\"11\", \"l\"=>
\"12\"}, \"wrong\"=>{\"h\"=>\"2\", \"m\"=>\"2\", \"l\"=>\"4\"}, \"blank
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"3\"}}, \"ROW2\"=>{\"correct
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"4\"}, \"wrong\"=>{\"h
\"=>\"4\", \"m\"=>\"6\", \"l\"=>\"6\"}, \"blank\"=>{\"h\"=>\"7\",
\"m\"=>\"5\", \"l\"=>\"6\"}}, \"ROW3\"=>{\"correct\"=>{\"h\"=>\"4\",
\"m\"=>\"6\", \"l\"=>\"7\"}, \"wrong\"=>{\"h\"=>\"6\", \"m\"=>\"7\",
\"l\"=>\"5\"}, \"blank\"=>{\"h\"=>\"7\", \"m\"=>\"9\", \"l\"=>
\"3\"}}}"]
I want to access its elements and create a database table from it, in the following format
ROW1 correct h=10, m=11,l=12
wrong h=2, m=2,l=4
blank h=2, m=4,l=3
...and similar for ROW2 and ROW3.
How can I do that?
I tried to access a value using
a["ROW1"]["Correct"]["h"]
...but it returns a nil value.
How to access the values of this array of hashes?
you need to first convert the string to hash which can be done as follows:
require 'json'
a = ["{\"ROW1\"=>{\"correct\"=>{\"h\"=>\"10\", \"m\"=>\"11\", \"l\"=>
\"12\"}, \"wrong\"=>{\"h\"=>\"2\", \"m\"=>\"2\", \"l\"=>\"4\"}, \"blank
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"3\"}}, \"ROW2\"=>{\"correct
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"4\"}, \"wrong\"=>{\"h
\"=>\"4\", \"m\"=>\"6\", \"l\"=>\"6\"}, \"blank\"=>{\"h\"=>\"7\",
\"m\"=>\"5\", \"l\"=>\"6\"}}, \"ROW3\"=>{\"correct\"=>{\"h\"=>\"4\",
\"m\"=>\"6\", \"l\"=>\"7\"}, \"wrong\"=>{\"h\"=>\"6\", \"m\"=>\"7\",
\"l\"=>\"5\"}, \"blank\"=>{\"h\"=>\"7\", \"m\"=>\"9\", \"l\"=>
\"3\"}}}"
]
hash_string = a[0]
hash = JSON.parse hash_string.gsub("\n", '').gsub('=>', ':')
# you access the hash now:
hash["ROW1"]["correct"]["h"]
# => 10
Btw, please note that there is a typo. Instead of Correct, the key is correct with small c instead of capital C.
Hope it helps : )

Ruby, accessing a nested value in a hash

I have the following hash. Using ruby, I want to get the value of "runs". I can't figure out how to do it. If I do my_hash['entries'], I can dig down that far. If I take that value and dig down lower, I get this error:
no implicit conversion of String into Integer:
{"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588, ...
Assuming that you want to lookup values by id, Array#detect comes to the rescue:
h = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]}]}
# ⇓⇓⇓⇓⇓⇓⇓ lookup element with id = 7
h['entries'].detect { |e| e['id'] == 7 }['runs']
.detect { |e| e['id'] == 2588 }
#⇒ { "id" => 2588 }
As you have an array inside the entries so you can access it using an index like this:
my_hash["entries"][0]["runs"]
You need to follow the same for accessing values inside the runs as it is also an array.
Hope this helps.
I'm not sure about your hash, as it's incomplete. So , guessing you have multiple run values like:
hash = {"id"=>2582, "entries"=>[{"id"=>"7", "runs"=>[{"id"=>2588}]},
{"id"=>"8", "runs"=>[{"id"=>2589}]},
{"id"=>"9", "runs"=>[{"id"=>2590}]}]}
Then, you can do
hash["entries"].map{|entry| entry["runs"]}
OUTPUT
[[{"id"=>2588}], [{"id"=>2589}], [{"id"=>2590}]]

How do I access a hash value that only exists in 1 attribute out of many?

So this one is a bit tricky.
I have an attribute that looks like this:
[22] pry(main)> n.media.meta_info[:response][:outputs]
=> [{"id"=>486,
"url"=>"http://some-video.com/by-fire.mp4",
"label"=>"webmp4",
"state"=>"finished",
"format"=>"mpeg4",
"type"=>"standard",
"frame_rate"=>30.06,
{"id"=>488848287,
"url"=>"http://some-video.com/by-fire.webm",
"label"=>"webwebm",
"state"=>"finished",
"format"=>"webm",
"type"=>"standard",
"frame_rate"=>30.06,
{"id"=>488848288,
"url"=>"http://some-video.com/by-fire.ogv",
"label"=>"webogv",
"state"=>"finished",
"format"=>"ogg",
"type"=>"standard",
"frame_rate"=>30.059,
{"id"=>488848289,
"url"=>
"https://zencoder-temp-storage-us-east-1.s3.amazonaws.com/",
"label"=>nil,
"state"=>"finished",
"format"=>"mpeg4",
"type"=>"standard",
"frame_rate"=>30.06,
"thumbnails"=>
[{"label"=>nil,
"images"=>
[{"dimensions"=>"56x100",
"file_size_bytes"=>15142,
"format"=>"PNG",
"url"=>"https://some-video.s3.amazonaws.com/uploads/video/video_file/id/by-fire.png"}]}],
"md5_checksum"=>nil}]
I am trying to access the thumbnails info, specifically the URL for the thumbnails.
I can't figure out how to get there though.
When I try to go the nested hash key of thumbnails it doesn't work:
[23] pry(main)> n.media.meta_info[:response][:outputs][:thumbnails]
TypeError: no implicit conversion of Symbol into Integer
from (pry):22:in `[]'
Thoughts?
The [{ at the beginning of the output indicates that an array is returned. You first need to find a element in the array that contains a thumbnails key:
outputs = n.media.meta_info[:response][:outputs]
output_with_thumbnail = outputs.find { |elem| elem.keys.include?('thumbnails') }
Then continue like this:
output_with_thumbnail['thumbnails']
If you're just trying to find the thumbnail, and don't care about the rest of the outputs, you can use #find like so:
thumbnails = n.media.meta_info[:response][:outputs].find {|it| it[:thumbnails] }[:thumbnails]
You have an array of hashes, thumbnails are in the 3rd:
n.media.meta_info[:response][:outputs][3][:thumbnails]
It looks like
outputs = n.media.meta_info[:response][:outputs]
is an Array of hashes. So, you need to iterate over them first:
outputs.each do |output|
# deal with each output here
end
You can check for :thumbnails like so:
if (thumbnails = output[:thumbnails])
# we've got thumbnails, deal with it here
end

How to make Rails.logger.debug print hash more readable

I'm using Rails.logger.debug print variables for debugging purposes. The issue is it prints hashes in an impossible to read format (can't distinguish keys from values). For example, I add the following lines to my code base
#code_base.rb
my_hash = {'a' => 'alligator', 'b'=>'baboon'}
Rails.logger.debug my_hash
Then I launch my rails app and type
tail -f log/development.log
But when my_hash gets printed, it looks like
bbaboonaalligator
The key and values are scrunched up, making it impossible to parse. Do you guys know what I should do to fix this?
Nevermind, I found the answer to my own question. I need to use
my_hash = {'a' => 'alligator', 'b'=>'baboon'}
Rails.logger.debug "#{my_hash.inspect}"
Then, it looks like
{"b"=>"baboon", "a"=>"aligator"}
It's even easier to read it when you use to_yaml eg:
logger.debug my_hash.to_yaml
Which is an easy to read format over multiple lines. The inspect method simply spews out a string.
my_hash = {'a' => 'alligator', 'b'=>'baboon'}
logger.debug "#{my_hash}"
Then, it looks like
{"b"=>"baboon", "a"=>"aligator"}
do not need inspect
There is an another way to do this. There is a ruby built in module pp.rb that is Pretty-printer for Ruby objects.
non-pretty-printed output by p is:
#<PP:0x81fedf0 #genspace=#<Proc:0x81feda0>, #group_queue=#<PrettyPrint::GroupQueue:0x81fed3c #queue=[[#<PrettyPrint::Group:0x81fed78 #breakables=[], #depth=0, #break=false>], []]>, #buffer=[], #newline="\n", #group_stack=[#<PrettyPrint::Group:0x81fed78 #breakables=[], #depth=0, #break=false>], #buffer_width=0, #indent=0, #maxwidth=79, #output_width=2, #output=#<IO:0x8114ee4>>
pretty-printed output by pp is:
#<PP:0x81fedf0
#buffer=[],
#buffer_width=0,
#genspace=#<Proc:0x81feda0>,
#group_queue=
#<PrettyPrint::GroupQueue:0x81fed3c
#queue=
[[#<PrettyPrint::Group:0x81fed78 #break=false, #breakables=[], #depth=0>],
[]]>,
#group_stack=
[#<PrettyPrint::Group:0x81fed78 #break=false, #breakables=[], #depth=0>],
#indent=0,
#maxwidth=79,
#newline="\n",
#output=#<IO:0x8114ee4>,
#output_width=2>
For more complex objects even with ActiveRecord, this could be achieved with a JSON.pretty_generate
Rails.logger.debug JSON.pretty_generate(my_hash.as_json)

JSON string to rails hash

I'm on Rails 2.3 and I'm trying to convert a string that is JSON-formatted to a Rails hash. However, when I use JSON.parse I get a JSON string without the delimiters:
{"source_id":40007,"object":"86088947610496.1","coursewalk_id":"86088947610477.1","description":"","image_uri":"db\/db-files\/
Image_2011-09-24_14.37.37__0000.jpg","latitude":"38.0113439821061","letter":"","letter_A":"","letter_B":"","letter_C":"","lett
er_D":"","letter_E":"","letter_F":"","longitude":"-78.7576854509104","number":"1","mcw_id":71}
Results of JSON.parse:
number1letter_Bcoursewalk_id86088947610477.1letter_Clatitude38.0113439821061letter_Dletter_Eletter_Fmcw_id71longitude-78.75768
54509104letterdescriptionobject86088947610496.1source_id40007letter_Aimage_uridb/db-files/Image_2011-09-24_14.37.37__0000.jpg
Code:
puts string_to_parse
fence_parsed = JSON.parse(string_to_parse)
puts fence_parsed
Any ideas?
Thanks,
Nick
That's just because you're using "puts". If you just type fence_parsed, or p fence_parsed you'll get what you're looking for. puts calls to_s. I hope this clears it up for you, if not let me know and I'll elaborate.

Resources