Refer to a hash where the key is an ip_address - ruby-on-rails

I've got a model that I need to group by the :sending_ip, which is a "cidr" column in the database.
#count_hash = Webhook.group('sending_ip').count
Resulting in this hash:
{#<IPAddr: IPv4:213.32.165.239/255.255.255.255>=>127000, #<IPAddr: IPv4:153.92.251.118/255.255.255.255>=>228000}
I cannot figure out how to reference this type of key. Below are some examples of the ways that I've tried to call these keys. All of them return nil or error.
#count_hash[#<IPAddr: IPv4:213.32.165.239/255.255.255.255>]
#count_hash["#<IPAddr: IPv4:213.32.165.239/255.255.255.255>"]
#count_hash[<IPAddr: IPv4:213.32.165.239/255.255.255.255>]
#count_hash["#<IPAddr: IPv4:213.32.165.239/255.255.255.255>"]
Elsewhere in my app, I've got a simpler example that works great. The other example groups by esp, which results in this hash:
{"hotmail"=>1000, "gmail"=>354000}
The second hash, I can refer to easily
#count_hash["gmail"]
To obtain the expected result of 354000
How can I achieve this same functionality with the previous hash that was grouped by sending_ip? Thank you in advance for your insight.

This:
#<IPAddr: IPv4:213.32.165.239/255.255.255.255>
is the result of calling #inspect on an instance of IPAddr. So the keys are IPAddr instances and you can say:
ip = IPAddr.new('213.32.165.239')
#count_hash[ip]
# 127000
Or you could iterate over the hash:
#count_hash.each { |ip, n| ... }
or over its keys:
#count_hash.keys.each { |ip| ... }
depending on what you need to do. You could even convert the keys to strings if that's more convenient:
#count_hash = #count_hash.transform_keys(&:to_s)
# or
#count_hash.transform_keys!(&:to_s)

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

Deleting a specific hash inside an array of hashes using a variable

I have an array of hashes like this:
"[{:id=>15, :name=>"Hockey", :num_of_boxes=>2, :total_price=>6.98}, {:id=>14, :name=>"Baseball", :num_of_boxes=>3, :total_price=>8.97}, {:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]"
In my controller I want to delete the hash where the ID is set as a variable elsewhere. How would I go about doing this?
This is what I was trying to get to work, and I think it's the right path? id would be set in the controller before this method runs:
new_array = eval(#garden.seed_cart).reject { |h| id.include? h['15'] }
Thanks for your help!
Try this:
arr.delete_if { |hash| id.include?(hash[:id]) }
Note (comparison to the #reject suggestion): #delete_if returns the unchanged array if there is nothing to delete. #reject returns nil. Also, #delete_if modifies the array in place, whereas #reject (without !) simply returns a changed version of the array but leaves the original unchanged.
edit
Note: the use of include? here assumes that there may be multiple integers that are being filtered out, i.e. if id (or ids) is actually an array. If you just need to filter one ID, you can use a straightforward comparison with hash[:id] == id inside the block. Thanks to smathy for pointing this out in the comments.
If you have this data:
data = [{:id=>15, :name=>"Hockey", :num_of_boxes=>2, :total_price=>6.98}, {:id=>14, :name=>"Baseball", :num_of_boxes=>3, :total_price=>8.97}, {:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]
And you want to remove this ids from data:
ids = [14,15]
You can do
new_array = data.reject { |h| ids.include? h[:id] }
And you get
new_array = [{:id=>5, :name=>"Basketball", :num_of_boxes=>2, :total_price=>5.98}]
Note: data in an array (not a string) and ids is an array too.

Why am I getting this TypeError - "can't convert Symbol into Integer"?

I have an array of hashes. Each entry looks like this:
- !map:Hashie::Mash
name: Connor H Peters
id: "506253404"
I'm trying to create a second array, which contains just the id values.
["506253404"]
This is how I'm doing it
second_array = first_array.map { |hash| hash[:id] }
But I'm getting this error
TypeError in PagesController#home
can't convert Symbol into Integer
If I try
second_array = first_array.map { |hash| hash["id"] }
I get
TypeError in PagesController#home
can't convert String into Integer
What am I doing wrong? Thanks for reading.
You're using Hashie, which isn't the same as Hash from ruby core. Looking at the Hashie github repo, it seems that you can access hash keys as methods:
first_array.map { |hash| hash.id }
Try this out and see if that works--make sure that it doesn't return the object_id. As such, you may want to double-check by doing first_array.map { |hash| hash.name } to see if you're really accessing the right data.
Then, provided it's correct, you can use a proc to get the id (but with a bit more brevity):
first_array.map(&:id)
This sounds like inside the map block that hash is not actually a hashie - it's an array for some reason.
The result is that the [] method is actually an array accessor method and requires an integer. Eg. hash[0] would be valid, but not hash["id"].
You could try:
first_array.flatten.map{|hash| hash.id}
which would ensure that if you do have any nested arrays that nesting is removed.
Or perhaps
first_array.map{|hash| hash.id if hash.respond_to?(:id)}
But either way you may end up with unexpected behaviour.

Resources