I am using the Google Civic Information API. It is giving me two arrays of hashes. I want to print information from both on the screen. Hash 1 has some integers as a k-v pair (officialIndices). These represent the index number for the corresponding object in the second hash. How can merge these two? I want to display the information from both hashes together. Maybe it would be better to replace the values of officialIndices with the indexed hash in the second array. Thanks for any advice!
Hash 1:
{
"name" => "President of the United States",
"divisionId" => "ocd-division/country:us",
"levels" => ["country"],
"roles" => ["headOfState", "headOfGovernment"],
"officialIndices" => [0]
}
Hash 2:
{
"name" => "Barack Obama",
"address" => [{
"line1" => "The White House",
"line2" => "1600 pennsylvania avenue nw",
"city" => "washington",
"state" => "DC",
"zip" => "20500"
}],
"party" => "Democratic",
"phones" => ["(202) 456-1111"],
"urls" => ["http://www.whitehouse.gov/"],
"photoUrl" => "http://www.whitehouse.gov/sites/default/files/imagecache/admin_official_lowres/administration-official/ao_image/president_official_portrait_hires.jpg",
"channels" => [
{ "type" => "GooglePlus", "id" => "+whitehouse" },
{ "type" => "Facebook", "id" => "whitehouse" },
{ "type" => "Twitter", "id" => "whitehouse" },
{ "type" => "YouTube", "id" => "barackobama" }
]
}
EDIT** To clarify, Hash 1 is the first hash in an array of hashes. Hash 2 is the first hash in an array of hashes. I would like to replace the number in officialIndice in Hash 1 with Hash 2. It's confusing me because some officialIndices have more than one number. Hope that makes sense.
Merge won't work; what will you do if officialIndices has multiple elements?
array1.each do |el1|
el1["officials"] = el1["officialIndices"].map { |idx|
array2[idx]
}
el1.delete("officialIndices")
end
(Note: this is destructive, i.e. it will change array1. If you want array1 unchanged, I'll rewrite.)
You can use Hash#merge with a block:
foo = { "name" => "President of the United States" }
bar = { "name" => "Barack Obama" }
foo.merge(bar) { |key, old_val, new_val| {description: old_val, value: new_val} }
=> {"name"=>{:description=>"President of the United States",
:value=>"Barack Obama"}}
So, you can specify your merge logic by this way. This solution effective if you have more than 1 overlapping key with similar logic.
You can use Hash#merge to merge information from two hashes. However, you have an overlapping key (name) in both, so you'll want to rename it either hash before merging:
# Rename "name" to "position_name" before merging to prevent collision
hash1["position_name"] = hash1.delete("name")
merged_hash = hash1.merge(hash2)
Related
I am new to working with Ruby. I am trying to get the first inner object (are they called Hashes in Ruby?) of an array called numerical_answers if one of the objects has a property of CustomerSatisfactionAnswer. See data below:
{
:rethink_id => "123",
:id => 102,
:campaign_id => 11,
:created_at => 2021-03-25 18:14:25 -0400,
:updated_at => 2021-03-25 18:14:31 -0400,
:status => 1,
:numerical_answers => [
[0] {
"id" => 103,
"number" => 2,
"type" => "CustomerSatisfactionAnswer"
},
[1] {
"id" => 104,
"number" => 7,
"type" => "MultipleChoice"
}
],
:language => "en",
}
See under numerical_answers there is one item in the array [0] and it has a type of CustomerSatisfactionAnswer. I need to be able to grab the value for number, but only if there is an object with that type. And it can be the first matching one in the array. Other matches don't matter. So I feel like I need to be doing some looping on numerical_answers until I find one that matches. But Ruby still confuses me! Help!
You can get the array of 'numerical_answers' by using following statement
variable[:numerical_answers]
If you want to find the matching type to "CustomerSatisfactionAnswer" in the above array use following code
matching_one = variable[:numerical_answers].find {|item| item["type"] == "CustomerSatisfactionAnswer"}
Note: In the above code 'variable' means your specified hash
So now matching_one contains
{
"id" => 103,
"number" => 2,
"type" => "CustomerSatisfactionAnswer"
}
To get the number from the above hash, use the following code
matching_one[:number]
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? }
My question is how to I pull out a specific object from this array that has an 'id' with the specific value of 888?
[{ "token" => "1212",
"category" => "A",
"name" => "page 2",
"id" => "888"
},
{ "token" => "3434",
"category" => "B",
"name" => "page 1",
"id" => "999",
}]
I have tried find_by, where, and a whole host of other things.
You can try using "select" on the array:
arr.select {|k| k['id'] == "888" }
This will return an array containing all array elements where the condition is met.
We've got a simple api endpoint that works like so:
def index
render json: Country.all
end
This is unfortunately giving us this output:
{
"countries" => [
[0] {
"countries" => {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
}
},
[1] {
"countries" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
Notice that the key for each individual object is the plural form of the key.
However, when we set the endpoint to work like so
def inded
render json: {countries: Country.all}
end
The output looks like so:
{
"countries" => [
[0] {
"country" => {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
}
},
[1] {
"country" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
I.e., correct.
However, setting the key like {countries: Country.all} is bad form, and I'd like to understand why rails is serializing each element with the collection key rather than the object key (that is, why it's plural and not singular for each country).
We have not overridden to_json or any other serialization methods. We are using the default rails model serializer (I tried making an explicit serializer, but there was no change in behavior). I cannot, for the life of me, figure out why it is pluralizing these keys.
Edit: There is even more weirdness. I was incorrect about the explicit serializer, when I set up a serializer (with just the attributes as it normally displays), I get this:
{
"countries" => [
[0] {
"id" => 1,
"iso" => "US",
"iso3" => "USA",
"iso_name" => "UNITED STATES",
"name" => "United States of Foo",
"numcode" => 840
},
[1] {
"countries" => {
"id" => 2,
"iso" => "CA",
"iso3" => "CAN",
"iso_name" => "CANADA",
"name" => "Canada",
"numcode" => 124
}
}
]
}
The first object has no key, and every other one is plural. I tested both in tests, and confirmed by making the actual API call.
I can't find anything that would override this other than an overridden <=> and to_s. These should not affect output in this way?
Mike, I think you copied and pasted something wrong, or you might just be confused.
Both outputs have the same results: Countries (Plural) as the main response, and country(Singular) for each individual inside countries. Or am I misreading?
I think what's happening here is that you're trying to specify the root key in a way that AM::S doesn't support.
Instead of render json: { countries: Country.all }, I'd recommend trying render json: Country.all, root: "countries" (specifying the root key is unnecessary if you're calling the serializer from within CountriesController, otherwise you need it to get the functionality you desire).
See https://github.com/rails-api/active_model_serializers/tree/0-8-stable#arrays for more information.
Here is the example from the crack documentation:
json = '{"posts":[{"title":"Foobar"}, {"title":"Another"}]}'
Crack::JSON.parse(json)
=> {"posts"=>[{"title"=>"Foobar"}, {"title"=>"Another"}]}
But how do I actually access the data in the hash?
I've tried the following:
array = Crack::JSON.parse(json)
array["posts"]
array["posts"] shows all the values, but I tried array["posts"]["title"] and it didn't work.
Here is what I am trying to parse as an example:
{"companies"=>[{"city"=>"San Mateo", "name"=>"Jigsaw", "address"=>"777 Mariners Island Blvd Ste 400", "zip"=>"94404-5059", "country"=>"USA", "companyId"=>4427170, "activeContacts"=>168, "graveyarded"=>false, "state"=>"CA"}], "totalHits"=>1}
I want to access the individual elements under companies....like city and name.
Like this?
hash = {
"companies" => [
{
"city" => "San Mateo",
"name" => "Jigsaw",
"address" => "777 Mariners Island Blvd Ste 400",
"zip" => "94404-5059",
"country" => "USA",
"companyId" => 4427170,
"activeContacts" => 168,
"graveyarded" => false,
"state" => "CA"
}
],
"totalHits" => 1
}
hash['companies'].each{ |i|
puts "city => #{i['city']}"
puts "name => #{i['name']}"
}
# >> city => San Mateo
# >> name => Jigsaw
hash['companies'][0]['city'] # => "San Mateo"
hash['companies'][0]['name'] # => "Jigsaw"
The problem is you didn't account for the array that companies points to.