dynamic loop in a hash Ruby on Rails - ruby-on-rails

I'm trying to create a dynamic loop within the hash #data below and
can't really seem to figure it out. I'm creating an annotatedtimeline-for-rails using the google api from here https://github.com/mcommons/annotatedtimeline-for-rails.
The array within the hash #data has to be dynamic i:e the day number has to be generated by a loop and the name of the product and number are dynamic as well. I'll
try to give an example in the loop below
#numdeployed is a number and comes from a table in the db
i should be generated by the loop
#data{
begin loop
i.day.ago.to_date => { :foo=>#numdeployed, :bar=>#numdeployed, :barbaz=>#numdeployed, :foobar=>#numdeployed },
end loop
}
The Original Data Hash looks like this
#data = {
1.day.ago.to_date => { :foo=>10, :bar=>40, :barbaz=>10, :foobar=>40 },
2.day.ago.to_date => { :foo=>10, :bar=>40, :barbaz=>10,:foobar=>40 },
3.day.ago.to_date => { :foo=>10, :bar=>40, :barbaz=>10,:foobar=>40 },
4.day.ago.to_date => { :foo=>10, :bar=>40, :barbaz=>10,:foobar=>40 },
5.day.ago.to_date => { :foo=>10, :bar=>40, :barbaz=>10,:foobar=>40 }
}
hope someone can help. Thanks

Are you looking for something like this?
#data = Hash[
n.times.map do |i|
[ (i + 1).day.ago.to_date, { :foo => 10, :bar => 40, :barbaz => 10, :foobar => 40 } ]
end
]
The n is however many pairs you want in your #data.

Related

Sort items in a nested hash by their key

I have a nested hash with unsorted keys:
given = {
"lorem" => {
:AA => "foo",
:GR => "foo",
:BB => "foo"
},
"ipsum" => {
:ZZ => "foo",
:GR => "foo",
}
}
What I'm trying to accomplish is a hash with sorted keys:
goal = {
"ipsum" => {
:GR => "foo",
:ZZ => "foo"
},
"lorem" => {
:AA => "foo",
:BB => "foo",
:GR => "foo"
}
}
I have experimented with .each method and sort_by
given.each { |topic| topic[:key].sort_by { |k, v| k } }
But I'm getting an error message: TypeError: no implicit conversion of Symbol into Integer
Any help is greatly appreciated!
PS: I noticed with gem pry the output is already sorted. But in IRB it's not.
You can use group_by, and transform_values to transform the values inside each hash, also using sort_by plus to_h:
given.transform_values { |value| value.sort.to_h }.sort.to_h
# {"ipsum"=>{:GR=>"foo", :ZZ=>"foo"}, "lorem"=>{:AA=>"foo", :BB=>"foo", :GR=>"foo"}}
You're getting an error because when iterating over a hash, you have to local variables within the block scope to use, the key and its value, you're assigning only one (topic) and trying to get its key, which would be trying to access a key in:
["lorem", {:AA=>"foo", :GR=>"foo", :BB=>"foo"}]
Which isn't possible as is an array. You can update your code to:
given.each do |topic, value|
...
end
But anyway you'll need a way to store the changes or updated and sorted version of that topic values.
given_hash = {"lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}, "ipsum"=>{:ZZ=>"foo", :GR=>"foo"}}
Get keys
given_hash.keys
=> ["lorem", "ipsum"]
New sorted hash
new_hash = {}
given_hash.keys.sort.each do |sorted_key|
new_hash[sorted_key] = given[sorted_key]
end
=> {"ipsum"=>{:ZZ=>"foo", :GR=>"foo"}, "lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}}
There can be a better way to do this.

Ruby & fetching hash values magic

I'm trying to parse out JSON data and create my own dictionary to show a subset of the data. The thing is, I'm noticing that my input data changes based on what is scanned (with nmap). Some elements might be an array value, whereas some might not. The combinations seem to be pretty broad.
For instance, here is the simplest input where only an IP address was found:
{
'host' => {
'address' => {
'addr' => '192.168.0.1'
},
'status' => {...}
}
}
But then, the IP and MAC address might be found:
{
'host' => {
'address' => [{
'addrtype' => 'ipv4',
'addr' => '192.168.0.1',
},{
'addrtype' => 'mac',
'mac' => '00:AA:BB:CC:DD:EE',
},
'status' => {...}
}]
}
Those are just a couple examples. Other variations I've seen:
`host.class` = Array
`address.class` = Hash
`host['status'].class` = Array
etc...
As I go through to parse the output, I am first checking if the element is an Array, if it is, I access the key/values one way, whereas if it's not an array, I essentially have to duplicate my code with a few tweaks to it, which doesn't seem very eloquent:
hash = {}
if hosts.class == Array
hosts.each do |host|
ip = if host['address'].class == Array
host['address'][0]['addr']
else
host['address']['addr']
end
hash[ip] = {}
end
else
ip = if hosts['address'].class == Array
hosts['address'][0]['addr']
else
hosts['address']['addr']
end
hash[ip] = {}
end
puts hash
end
In the end, I'm just trying to find a better/eloquent way to produce a hash like below, while accounts for the possibility that an element may/may not be an Array:
{
'192.168.0.1' => {
'mac' => '00:aa:bb:cc:dd:ee',
'vendor' => 'Apple',
'ports' => {
'80' => {
'status' => 'open',
'service' => 'httpd'
}
'443' => {
'status' => 'filtered',
'service' => 'httpd'
}
}
},
192.168.0.2 => {
...
}
}
If there a ruby method that I haven't run across yet that will make this more fluid?
Not really... but you can make it always an array eg by doing something like:
hosts = [hosts] unless hosts.is_a?(Array)
or similar... then just pass that to your now-non-duplicated code. :)
The 20 lines of code in your question can be reduced to a single line using Array#wrap instead of conditionals, and using Enumerable#map instead of Enumerable#each:
Array.wrap(hosts).map { |host| [Array.wrap(host['address']).first['addr'], {}] }.to_h
Now that's magic!

Grabbing a specific hash in an array that meets a specific criteria

I have a huge array full of a bunch of hashes. What I need to do is single out one index hash from the array that meets a specific criteria. (doing this due to an rspec test, but having trouble singling out one of them)
My array is like this
[
{
"name" => "jon doe",
"team" => "team2",
"price" => 2000,
"eligibility_settings" => {}
},
{
"name" => "jonny doe",
"team" => "team1",
"value" => 2000,
"eligibility_settings" => {
"player_gender" => male,
"player_max_age" => 26,
"player_min_age" => 23,
"established_union_only" => true
}
},
{
"name" => "jonni doe",
"team" => "team3",
"price" => 2000,
"eligibility_settings" => {}
},
]
I need to single out the second one, based on its eligibility settings. I just took three of them from my array, have lots more, so simple active record methods like (hash.second) won't work in this instance.
I've tried things like
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
However when I try this, I get a nil response. (which is odd)
I've also looked into using the ruby detect method, which hasn't gotten me anywhere either
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Would anybody have any idea what to do with this one?
Notes
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Is is players or Players ?
Why is it plural?
If you can call map on team, it probably should be plural
Why do you convert to a hash?
eligibility_settings? isn't a key in your hash. eligibility_settings is
eligibility_settings can be a hash, but it cannot be true
If you want to check if it isn't empty, use !h['eligibility_settings'].empty?
Possible solution
You could use :
data = [
{
'name' => 'jon doe',
'team' => 'team2',
'price' => 2000,
'eligibility_settings' => {}
},
{
'name' => 'jonny doe',
'team' => 'team1',
'value' => 2000,
'eligibility_settings' => {
'player_gender' => 'male',
'player_max_age' => 26,
'player_min_age' => 23,
'established_union_only' => true
}
},
{
'name' => 'jonni doe',
'team' => 'team3',
'price' => 2000,
'eligibility_settings' => {}
}
]
p data.find { |h| !h['eligibility_settings'].empty? }
# {"name"=>"jonny doe", "team"=>"team1", "value"=>2000, "eligibility_settings"=>{"player_gender"=>"male", "player_max_age"=>26, "player_min_age"=>23, "established_union_only"=>true}}
If h['eligibility_settings'] can be nil, you can use :
data.find { |h| !h['eligibility_settings'].blank? }
or
data.find { |h| h['eligibility_settings'].present? }

Sort rails hash based on array of items

I have an array like this:
['one','three','two','four']
I have a array of hash like this:
[{'three' => {..some data here..} }, {'two' => {..some data here..} }, {:total => some_total }] # etc...
I want to sort the array of hashes by the first array. I know I can do:
array_of_hashes.sort_by{|k,v| k.to_s} to sort them and it will sort by the key
( and the .to_s to convert :total to a string )
How can I make this happen?
Edit:
I was incorrect about how this is setup, it is actually like this:
{'one' => {:total => 1, :some_other_value => 5}, 'two' => {:total => 2, :some_other_value => 3} }
If I need to put this in a new question, just let me know and I will do that.
Thank you
similar to ctcherry answer, but using sort_by.
sort_arr = ['one','three','two','four']
hash_arr = [{'three' => {..some data here..} }, {'two' => {..some data here..} }]
hash_arr.sort_by { |h| sort_arr.index(h.keys.first) }
The index method of Array is your friend in this case:
sort_list = ['one','three','two','four']
data_list = [{'three' => { :test => 3 } }, {'two' => { :test => 2 } }, {'one' => { :test => 1 } }, {'four' => { :test => 4 } }]
puts data_list.sort { |a,b|
sort_list.index(a.keys.first) <=> sort_list.index(b.keys.first)
}.inspect
Resulting in, the same order as the source array:
[{"one"=>{:test=>1}}, {"three"=>{:test=>3}}, {"two"=>{:test=>2}}, {"four"=>{:test=>4}}]

How to "trasform" an array of hash so that you can customize logic to access its data?

I am using Ruby on Rails 3 and I would like to "trasform" the following array so that I can use my custom logic to access its data.
This is the original array from which I have to build a new one
[
{
"account" => {
"id" => 45,
"name" => "Test_name",
"..." => ..."
}
},
{
"other" => {
"sub_other" => {...}
}
}
]
I would like to trasform the above array so that I can do in my controller something like
array_name[45]
# => {
"name" => "Test_name",
"..." => ..."
}
but only for the account hashs. The other hash should remain untouched.
How can I proceed to build the new array?
If I understand your requirements correctly, I think you are better off constructing a hash from account id to account data. Perhaps something like this will work:
arr = [
{
"account" => {
"id" => 45,
"name" => "Test_name",
"..." => "..."
}
},
{
"other" => {
"sub_other" => "..."
}
}
]
account_hashes = arr.select {|item| item.keys.first == "account"}
answer = account_hashes.inject({}) do |acc, item|
acc[item["account"].delete("id")] = item["account"]
acc
end

Resources