Pulling together two results in Ruby - ruby

I have the result of one API (FourSquare) giving me this..
[["4e01728f814d9dac7d52b93d","Bark Boutique",40.7143528,-74.0059731],["4d9f92dfaffda35d5db2a748","Bark Boutique",40.7143528,-74.0059731]]
I send these results to another API that gives me a result like this:
[{"4e01728f814d9dac7d52b93d":yes},{"4d9f92dfaffda35d5db2a748":no}]
What I want to do is compare the second results I get to the first and combine them. So I would get back:
[["4e01728f814d9dac7d52b93d","Bark Boutique",40.7143528,-74.0059731, yes],["4d9f92dfaffda35d5db2a748","Bark Boutique",40.7143528,-74.0059731, no]]
However some of the results in the first set will not all be returned in the second set. So I need to find out which ones are the same by the id[0] and then pull these out and combine them again.
What is the best way to do this in ruby? I have tried using map, but can only extract the data from each not both at the same time?
Edit for real data:
array2 =
[{"4bed4208bac3c9b692fcfde9"=>743.0}, {"4e21b6f052b1f82ffba120b5"=>789.0}, {"4b646071f964a52052ae2ae3"=>921.0}, {"4bb504a30ef1c9b6dbc2f412"=>99.0}, {"4b426369f964a520e3d225e3"=>80.0}, {"4c4f275651c2c9288af1859f"=>254.0}, {"4b92cb0bf964a520501c34e3"=>468.0}, {"4b425f85f964a52092d225e3"=>27.0}, {"4bd86cb6e914a593c92f53fa"=>512.0}, {"4e687a6bb3ad5d9197518ed6"=>622.0}, {"4b4447f8f964a5206cf325e3"=>73.0}, {"4b425ec9f964a52086d225e3"=>26.0}, {"4b484917f964a520184b26e3"=>328.0}, {"4b426047f964a520a4d225e3"=>37.0}, {"4c978b274f16b71312c2ce3f"=>253.0}, {"4b6de739f964a520769a2ce3"=>81.0}, {"4b48c8a8f964a520cb5626e3"=>167.0}, {"4bb475f449bdc9b65bcb0c10"=>80.0}, {"4c126e3c82a3c9b60ab0f9f8"=>739.0}, {"4bd8b0442e6f0f4754240808"=>210.0}, {"4bb61c6bef159c74ff6b75f7"=>231.0}, {"4b56243af964a5204f0228e3"=>56.0}, {"4b411f2bf964a52082c125e3"=>0.0}, {"4b48a60ff964a5208c5126e3"=>211.0}, {"4baded59f964a52031733be3"=>514.0}, {"4b40ce65f964a5205ebb25e3"=>124.0}, {"4b444648f964a52049f325e3"=>81.0}, {"4bb0eb08f964a520006a3ce3"=>376.0}, {"4f63b0b5e4b087553c2ae4fa"=>586.0}, {"4b9a86c4f964a520f2bd35e3"=>192.0}, {"4cb995490180721e03e09461"=>125.0}, {"4dc58ce152b1e8f9f7d7378b"=>955.0}, {"4b92c695f964a520aa1a34e3"=>20.0}, {"4c582015a7d976b0130cddee"=>484.0}, {"4c8ccb34509e3704d9533655"=>743.0}, {"4b48f87ff964a520096026e3"=>48.0}, {"4c1a1c70838020a137aae661"=>640.0}, {"4b894378f964a520e72632e3"=>55.0}, {"4e8b7820be7b1b0656b1f927"=>666.0}, {"4e02726dc65b8061424b59f1"=>78.0}, {"4b4261e4f964a520c6d225e3"=>57.0}, {"4ba55291f964a5209afa38e3"=>77.0}, {"4c714ddcb5a5236acb995252"=>473.0}, {"4b7451e5f964a520fad42de3"=>80.0}, {"4b490136f964a520a56126e3"=>71.0}, {"4d987f7961a3a1cd32aace42"=>1008.0}, {"4dbd63785da3ff58ec6192b1"=>622.0}, {"4b71bb30f964a5200b592de3"=>640.0}, {"4be6c014bcef2d7f476805e5"=>1016.0}, {"4bc762a32f94d13aebd2117f"=>577.0}]
array1=
[["4b411f2bf964a52082c125e3", "The Three Pigeons", 51.236318, -0.57055], ["4b444648f964a52049f325e3", "The Royal Oak", 51.23555937678702, -0.5702378403809515], ["4b92c695f964a520aa1a34e3", "Slug And Lettuce", 51.237156, -0.571021], ["4b490136f964a520a56126e3", "The Robin Hood", 51.23603403568268, -0.568686], ["4b425f85f964a52092d225e3", "The Guildford Tup", 51.237734, -0.5703823], ["4b48f87ff964a520096026e3", "The Keep", 51.234704, -0.572574], ["4b426369f964a520e3d225e3", "The Five & Lime", 51.236908, -0.573695], ["4b56243af964a5204f0228e3", "The Albany", 51.23687122552597, -0.5666781994529876], ["4b426047f964a520a4d225e3", "The Kings Head", 51.234176, -0.573656], ["4b4261e4f964a520c6d225e3", "The Live and Let Live", 51.238477, -0.573306], ["4b425ec9f964a52086d225e3", "The Star Inn - Shepherd Neame", 51.23501026190194, -0.5749610066413879], ["4cb995490180721e03e09461", "Prince Albert", 51.242471, -0.572899], ["4e02726dc65b8061424b59f1", "Bar Mambo", 51.236896, -0.577263], ["4b7451e5f964a520fad42de3", "The Rodboro Buildings (Wetherspoon)", 51.236624141592365, -0.5775332450866699], ["4b6de739f964a520769a2ce3", "The White House", 51.23463575311113, -0.5773776769638062], ["4bb504a30ef1c9b6dbc2f412", "The Britannia - Shepherd Neame", 51.233105063438416, -0.5760687589645386], ["4b4447f8f964a5206cf325e3", "The George Abbot", 51.235186599066246, -0.5779409408569336], ["4b894378f964a520e72632e3", "The Boatman", 51.23155028087051, -0.572927], ["4bb475f449bdc9b65bcb0c10", "The Keystone", 51.23437208365849, -0.5779758095741272], ["4ba55291f964a5209afa38e3", "Rogues Bar", 51.23763173808256, -0.5610001087188721], ["4b40ce65f964a5205ebb25e3", "The Drummond", 51.24133950313797, -0.5758380889892578], ["4b48c8a8f964a520cb5626e3", "The Stok", 51.24272843225208, -0.5718989403261525], ["4c4f275651c2c9288af1859f", "The Parkway", 51.248229, -0.569356], ["4b48a60ff964a5208c5126e3", "The King's Head", 51.24666037427897, -0.5728936419289142], ["4b9a86c4f964a520f2bd35e3", "Ye Olde Ship Inn", 51.225673503520696, -0.5796146392822266], ["4c582015a7d976b0130cddee", "Wates House", 51.2420380341127, -0.5908584594726562], ["4b484917f964a520184b26e3", "The Rowbarge", 51.25055105804697, -0.5729025186239382], ["4bd86cb6e914a593c92f53fa", "The Wooden Bridge", 51.248547, -0.58514], ["4bd8b0442e6f0f4754240808", "The Seahorse", 51.218605041503906, -0.569018], ["4bb61c6bef159c74ff6b75f7", "The Astolat Public House", 51.23704061748392, -0.5893993377685547], ["4c978b274f16b71312c2ce3f", "The Queen Victoria", 51.21475338935852, -0.567119], ["4bb0eb08f964a520006a3ce3", "Anchor & Horseshoes", 51.254823, -0.548787], ["4c126e3c82a3c9b60ab0f9f8", "The Garage Tavern", 51.261162, -0.586647], ["4bed4208bac3c9b692fcfde9", "The Cricketers", 51.254246288978116, -0.6047425123927289], ["4b92cb0bf964a520501c34e3", "Horse & Groom", 51.24614672635736, -0.5279016494750977], ["4e8b7820be7b1b0656b1f927", "Apple Tree Pub", 51.2460676, -0.61427766], ["4dc58ce152b1e8f9f7d7378b", "Royal Oak", 51.248792, -0.626987], ["4c1a1c70838020a137aae661", "Withies Inn", 51.21199, -0.621551], ["4baded59f964a52031733be3", "The Jolly Farmer", 51.194106, -0.558244], ["4e21b6f052b1f82ffba120b5", "Compton Royal British Legion", 51.21349872454546, -0.6290990092597657], ["4b646071f964a52052ae2ae3", "The Jolly Farmer", 51.27866916930163, -0.5856227874755859], ["4d987f7961a3a1cd32aace42", "White Hart", 51.25011, -0.636736], ["4c8ccb34509e3704d9533655", "The Harrow Inn", 51.213387, -0.6316709518432617], ["4b71bb30f964a5200b592de3", "Bull's Head", 51.253260091783105, -0.5042177438735962], ["4f63b0b5e4b087553c2ae4fa", "The freeholders", 51.194189, -0.603889], ["4bc762a32f94d13aebd2117f", "The Cricketers", 51.194975, -0.608211], ["4be6c014bcef2d7f476805e5", "Worplesdon Place (Beef Eater Grill)", 51.27501810816803, -0.6078529357910156], ["4dbd63785da3ff58ec6192b1", "Scratchers", 51.19211, -0.60234], ["4e687a6bb3ad5d9197518ed6", "Three Lions - Shepherd Neame", 51.19198564344851, -0.6023865938186646], ["4c714ddcb5a5236acb995252", "The White heart Pub", 51.200254, -0.603593]]
need to match the id 4e687a6bb3ad5d9197518ed6 in array 1 with 4e687a6bb3ad5d9197518ed6 value in array 2...

array1 = [["4e01728f814d9dac7d52b93d","Bark Boutique",40.7143528,-74.0059731],
["4d9f92dfaffda35d5db2a748","Bark Boutique",40.7143528,-74.0059731]]
array2 = [{"4e01728f814d9dac7d52b93d"=>:yes},{"4d9f92dfaffda35d5db2a748"=>:no}]
array1.zip(array2).map do |ar1,ar2|
ar2[ar1[0]] ? ar1 << ar2[ar1[0]] : nil
end.compact
Edit:
In the original question the elements with same key and also they have the same index, but from edited question I understood that index can be not identical. Then:
array1.clone.each do |m|
result = array2.detect { |hash| hash[m[0]] }
m << result[m[0]] if result
end
The clone is essential because the construction m << value modifies the object.

Array#zip allows you to combine several arrays. The form using a block might be the one you want.

Related

When I click the mouse how do I make it so the arrays re shuffle and have a different output?

The goal of the project is to make a MadLib. I want the array to shuffle each time the mouse is clicked, how would I go about doing that?
String madLib = "I went to #place# with #person#. I know #person# from when we #event#. At #place# we saw #thing#. It was #adjective# so we ran away to #otherPlace#. ";
String[] array1 = {"Pakistan", "The Pentagon", "Universal Studios Sound Stage No. 5", "The basement of the United States Embassy in Iran", "Uncle Randy's Attic"};
String[] array2 = {"Former President Bill Clinton", "Ten Dolla Founding Fatha Alexander Hamilton", "Former Bufffalo Bills Running Back Orenthal James 'OJ' Simpson ", "Clifford From Clifford The Big Red Dog", "Director and 2 time oscar winner Quentin Tarantino "};
String[] array3 = {"Stole the entire contents of Fort Knox", "Taught John D. Rockefeller how to get oil", "Tried to but failed to prevent the Cold War", "Tried to save Brandon Lee", "Attemted to rob a Boost Mobile and got locked in"};
String[] array4 = {"A taxidermied lion with three legs ", "cryogenically frozen Walt Disney", "A below average height but above average speed brown colored horse", "A bucket of warm cow milk", "A replica of political podcaster Ben Shapiro"};
String[] array5 = {"Barking", "Running around", "Eating the Travis Scott meal from McDonalds", "Watching Season 1 of Mickeymouse Clubhouse", "Verbally abusing a cardboard cutout of Air Buddy for the Air Bud movies"};
String[] array6 = {"A random house", "the museum of cats", "The dog adoption center", "The Wendys drivethrough line", "The window and light fixture store"};
void setup() {
}
void draw(){
}
void mousePressed(){
int index1 = int(random(array1.length));
int index2 = int(random(array2.length));
int index3 = int(random(array3.length));
int index4 = int(random(array4.length));
int index5 = int(random(array5.length));
int index6 = int(random(array6.length));
madLib = madLib.replace("#place#", (array1[index1]));
madLib = madLib.replace("#person#", (array2[index2]));
madLib = madLib.replace("#event#", (array3[index3]));
madLib = madLib.replace("#thing#", (array4[index4]));
madLib = madLib.replace("#adjective#", (array5[index5]));
madLib = madLib.replace("#otherPlace#", (array6[index6]));
println(madLib);
}
What you have written in mousePressed modifies the original madLib string, replacing all the hash delimited parameters with new information. That works fine the first time it is run and the string that is printed has those parameters replaced so you get the right output.
But now the madLib string doesn't contain any hash delimited parameters, so when mousePressed runs again none of the replace commands does anything because the hash delimited parameters they are replacing no longer exist.
So you need to modify a copy of the string and do your replacements on the copy and leave the original string alone. Thanks to #GeorgeProfenza for this code sample:
String madLib = "I went to #place# with #person#. I know #person# from when we #event#. At #place# we saw #thing#. It was #adjective# so we ran away to #otherPlace#. ";
String[] array1 = {"Pakistan", "The Pentagon", "Universal Studios Sound Stage No. 5", "The basement of the United States Embassy in Iran", "Uncle Randy's Attic"};
String[] array2 = {"Former President Bill Clinton", "Ten Dolla Founding Fatha Alexander Hamilton", "Former Bufffalo Bills Running Back Orenthal James 'OJ' Simpson ", "Clifford From Clifford The Big Red Dog", "Director and 2 time oscar winner Quentin Tarantino "};
String[] array3 = {"Stole the entire contents of Fort Knox", "Taught John D. Rockefeller how to get oil", "Tried to but failed to prevent the Cold War", "Tried to save Brandon Lee", "Attemted to rob a Boost Mobile and got locked in"};
String[] array4 = {"A taxidermied lion with three legs ", "cryogenically frozen Walt Disney", "A below average height but above average speed brown colored horse", "A bucket of warm cow milk", "A replica of political podcaster Ben Shapiro"};
String[] array5 = {"Barking", "Running around", "Eating the Travis Scott meal from McDonalds", "Watching Season 1 of Mickeymouse Clubhouse", "Verbally abusing a cardboard cutout of Air Buddy for the Air Bud movies"};
String[] array6 = {"A random house", "the museum of cats", "The dog adoption center", "The Wendys drivethrough line", "The window and light fixture store"};
void setup() {
}
void draw() {
}
void mousePressed() {
int index1 = int(random(array1.length));
int index2 = int(random(array2.length));
int index3 = int(random(array3.length));
int index4 = int(random(array4.length));
int index5 = int(random(array5.length));
int index6 = int(random(array6.length));
String madLibResult = madLib.replace("#place#", (array1[index1]));
madLibResult = madLibResult.replace("#person#", (array2[index2]));
madLibResult = madLibResult.replace("#event#", (array3[index3]));
madLibResult = madLibResult.replace("#thing#", (array4[index4]));
madLibResult = madLibResult.replace("#adjective#", (array5[index5]));
madLibResult = madLibResult.replace("#otherPlace#", (array6[index6]));
println(madLibResult);
}

I want to create a new local variable from the sum of two others in Ruby but I'm stuck

I am trying to change one example to take a user input rather than using hard coded values then use those local variables to work out items needed.
So far my code looks like this:
print "Number of cars available today."
cars = gets.chomp()
print "Number of available seats in the car."
space_in_a_car = gets.chomp()
print "Number of drivers available."
drivers = gets.chomp()
print "Number of passagers that need transport."
passangers = gets.chomp
cars_not_driven = #{cars} - #{drivers}
cars_driven = drivers
carpool_capacity = #{cars_driven} * #{space_in_a_car}
average_passanger_per_car = #{passangers} / #{drivers}
print "The number of cars being driven today is #{cars_driven}.\n"
print "The number of cars not being driven today is #{cars_not_driven}.\n"
print "We have #{carpool_capacity} cars available.\n"
print "So we need to carry #{average_passanger_per_car} passangers per car to make sure we can transport everyone.\n"
The code will run without throwing any errors but of course because I am not getting the correct commands in:
cars_not_driven = #{cars} - #{drivers}
cars_driven = drivers
carpool_capacity = #{cars_driven} * #{space_in_a_car}
average_passanger_per_car = #{passangers} / #{drivers}
the only value I am getting in the return is:
print "The number of cars being driven today is #{cars_driven}.\n"
How should I be writing:
cars_not_driven = #{cars} - #{drivers} etc
to get the number of cars_not_driven?
I don't understand very well why you use this #{var} and <br>. If I am right that you want to use plain ruby, this should be the solution:
print "Number of cars available today."
cars = gets.chomp().to_i
print "Number of available seats in the car."
space_in_a_car = gets.chomp().to_i
print "Number of drivers available."
drivers = gets.chomp().to_i
print "Number of passagers that need transport."
passangers = gets.chomp.to_i
cars_not_driven = cars - drivers
cars_driven = drivers
carpool_capacity = cars_driven * space_in_a_car
average_passanger_per_car = passangers / drivers
print "The number of cars being driven today is #{cars_driven}.\n"
print "The number of cars not being driven today is #{cars_not_driven}.\n"
print "We have #{carpool_capacity} cars available.\n"
print "So we need to carry #{average_passanger_per_car} passangers per car to make sure we can transport everyone.\n"
When you use gets Ruby is expecting and returning a String. So variables car, drivers etc are all String.
In order to do integer operation over them, you need to convert them to integers. In Ruby you can do this using .to_i.
Now with that information, try:
cars_not_driven = cars.to_i - drivers.to_i
cars_driven = drivers.to_i
carpool_capacity = cars_driven * space_in_a_car.to_i
average_passanger_per_car = passangers.to_i / drivers.to_i
You can check the class of a variable using .class. Here:
cars = gets.chomp()
10
# => "10"
cars.class
# => String
drivers = gets.chomp()
20
# => "20"
drivers.class
# => String
Now lets add them:
cars + drivers
# => "1020"
Since they are string, + operator is adding two strings to one. Not something you intended. Now try this:
cars.to_i + drivers.to_i
# => 30

How do I drill down into a JSON object using Ruby's JSON gem

I have some JSON returned from Google Maps API.
{"results"=>
[{"address_components"=>
[{"long_name"=>"1600", "short_name"=>"1600", "types"=>["street_number"]},
{"long_name"=>"President's Park",
"short_name"=>"President's Park",
"types"=>["establishment"]},
{"long_name"=>"Pennsylvania Avenue Northwest",
"short_name"=>"Pennsylvania Ave NW",
"types"=>["route"]},
{"long_name"=>"Washington",
"short_name"=>"Washington",
"types"=>["locality", "political"]},
{"long_name"=>"District of Columbia",
"short_name"=>"DC",
"types"=>["administrative_area_level_1", "political"]},
{"long_name"=>"United States",
"short_name"=>"US",
"types"=>["country", "political"]},
{"long_name"=>"20500", "short_name"=>"20500", "types"=>["postal_code"]}],
"formatted_address"=>
"1600 Pennsylvania Avenue Northwest, President's Park, Washington, DC 20500, USA",
"geometry"=>
{"location"=>{"lat"=>38.8977332, "lng"=>-77.0365305},
"location_type"=>"ROOFTOP",
"viewport"=>
{"northeast"=>{"lat"=>38.8990821802915, "lng"=>-77.0351815197085},
"southwest"=>{"lat"=>38.8963842197085, "lng"=>-77.03787948029151}}},
"partial_match"=>true,
"types"=>["street_address"]}],
"status"=>"OK"}
I'm trying to access the latitude and longitude like so:
parsed = JSON.parse(data)
p parsed["results"]["location"]["lat"]
p parsed["results"]["location"]["lng"]
When I do so, my code throws and error: "no implicit conversion of String into Integer (TypeError).
I will be very grateful to anyone who can shed some light onto my problem. Thank you.
So, in your case it would be
p parsed["results"][0]["geometry"]["location"]
# => {"lat"=>38.8977332, "lng"=>-77.0365305}

How to parse a more complicated JSON object in Ruby on Sinatra

I'm a Java guy, new to Ruby. I've been playing with it just to see what it can do, and I'm running into an issue that I can't solve.
I decided to try out Sinatra, again, just to see what it can do, and decided to play with the ESPN API and see if I can pull the venue of a team via the API.
I'm able to make the call and get the data back, but I am having trouble parsing it:
{"sports"=>[{"name"=>"baseball", "id"=>1, "uid"=>"s:1", "leagues"=>[{"name"=>"Major League Baseball", "abbreviation"=>"mlb", "id"=>10, "uid"=>"s:1~l:10", "groupId"=>9, "shortName"=>"MLB", "teams"=>[{"id"=>17, "uid"=>"s:1~l:10~t:17", "location"=>"Cincinnati", "name"=>"Reds", "abbreviation"=>"CIN", "color"=>"D60042", "venues"=>[{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}], "links"=>{"api"=>{"teams"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17"}, "news"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"}, "notes"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}}, "web"=>{"teams"=>{"href"=>"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}}, "mobile"=>{"teams"=>{"href"=>"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}], "resultsOffset"=>0, "resultsLimit"=>50, "resultsCount"=>1, "timestamp"=>"2013-08-04T14:47:13Z", "status"=>"success"}
I want to pull the venues part of the object, specifically the name value. Every time I try to parse it I end up getting an error along the lines of "cannot change from nil to string" and then also I've gotten an integer to string error.
Here's what i have so far:
get '/venue/:team' do
id = ids[params[:team]]
url = 'http://api.espn.com/v1/sports/baseball/mlb/teams/' + id + '?enable=venues&apikey=' + $key
resp = Net::HTTP.get_response(URI.parse(url))
data = resp.body
parsed = JSON.parse(resp.body)
#venueData = parsed["sports"]
"Looking for the venue of the #{params[:team]}, which has id " + id + ", and here's the data returned: " + venueData.to_s
end
When I do parsed["sports"} I get:
[{"name"=>"baseball", "id"=>1, "uid"=>"s:1", "leagues"=>[{"name"=>"Major League Baseball", "abbreviation"=>"mlb", "id"=>10, "uid"=>"s:1~l:10", "groupId"=>9, "shortName"=>"MLB", "teams"=>[{"id"=>17, "uid"=>"s:1~l:10~t:17", "location"=>"Cincinnati", "name"=>"Reds", "abbreviation"=>"CIN", "color"=>"D60042", "venues"=>[{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}], "links"=>{"api"=>{"teams"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17"}, "news"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"}, "notes"=>{"href"=>"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}}, "web"=>{"teams"=>{"href"=>"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}}, "mobile"=>{"teams"=>{"href"=>"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}]
But nothing else parses. Please help!
Like I said, I'm not trying to do anything fancy, just figure out Ruby a little for fun, but I have been stuck on this issue for days now. Any help would be appreciated!
EDIT:
JSON straight from the API:
{"sports" :[{"name" :"baseball","id" :1,"uid" :"s:1","leagues" :[{"name" :"Major League Baseball","abbreviation" :"mlb","id" :10,"uid" :"s:1~l:10","groupId" :9,"shortName" :"MLB","teams" :[{"id" :17,"uid" :"s:1~l:10~t:17","location" :"Cincinnati","name" :"Reds","abbreviation" :"CIN","color" :"D60042","venues" :[{"id" :83,"name" :"Great American Ball Park","city" :"Cincinnati","state" :"Ohio","country" :"","capacity" :0}],"links" :{"api" :{"teams" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17"},"news" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news"},"notes" :{"href" :"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes"}},"web" :{"teams" :{"href" :"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public"}},"mobile" :{"teams" :{"href" :"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public"}}}}]}]}],"resultsOffset" :0,"resultsLimit" :50,"resultsCount" :1,"timestamp" :"2013-08-05T19:44:32Z","status" :"success"}
The result of data.inspect:
"{\"sports\" :[{\"name\" :\"baseball\",\"id\" :1,\"uid\" :\"s:1\",\"leagues\" :[{\"name\" :\"Major League Baseball\",\"abbreviation\" :\"mlb\",\"id\" :10,\"uid\" :\"s:1~l:10\",\"groupId\" :9,\"shortName\" :\"MLB\",\"teams\" :[{\"id\" :17,\"uid\" :\"s:1~l:10~t:17\",\"location\" :\"Cincinnati\",\"name\" :\"Reds\",\"abbreviation\" :\"CIN\",\"color\" :\"D60042\",\"venues\" :[{\"id\" :83,\"name\" :\"Great American Ball Park\",\"city\" :\"Cincinnati\",\"state\" :\"Ohio\",\"country\" :\"\",\"capacity\" :0}],\"links\" :{\"api\" :{\"teams\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17\"},\"news\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news\"},\"notes\" :{\"href\" :\"http://api.espn.com/v1/sports/baseball/mlb/teams/17/news/notes\"}},\"web\" :{\"teams\" :{\"href\" :\"http://espn.go.com/mlb/team/_/name/cin/cincinnati-reds?ex_cid=espnapi_public\"}},\"mobile\" :{\"teams\" :{\"href\" :\"http://m.espn.go.com/mlb/clubhouse?teamId=17&ex_cid=espnapi_public\"}}}}]}]}],\"resultsOffset\" :0,\"resultsLimit\" :50,\"resultsCount\" :1,\"timestamp\" :\"2013-08-05T19:44:24Z\",\"status\" :\"success\"}"
parsed["sports"] does not exist, parse your input and inspect it/ dump it
With the data you've provided in the question, you can get to the venues information like this:
require 'json'
json = JSON.parse data
json["sports"].first["leagues"].first["teams"].first["venues"]
# => [{"id"=>83, "name"=>"Great American Ball Park", "city"=>"Cincinnati", "state"=>"Ohio", "country"=>"", "capacity"=>0}]
By replacing each of the first calls with an iterator, you can search through without knowing where the data is:
json["sports"].each{|h|
h["leagues"].each{|h|
h["teams"].each{|h|
venues = h["venues"].map{|h| h["name"]}.join(", ")
puts %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
}
}
}
This outputs:
name: Cincinnati Reds venues: Great American Ball Park
Depending on how stable the response data is you may be able to cut out several of the iterators:
json["sports"].first["leagues"]
.first["teams"]
.each{|h|
venues = h["venues"].map{|h| h["name"] }.join(", ")
puts %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
}
and you'll most likely want to save the data, so something like each_with_object is helpful:
team_and_venues = json["sports"].first["leagues"]
.first["teams"]
.each_with_object([]){|h,xs|
venues = h["venues"].map{|h| h["name"]}.join(", ")
xs << %Q!name: #{h["location"]} #{h["name"]} venues: #{venues}!
}
# => ["name: Cincinnati Reds venues: Great American Ball Park"]
team_and_venues
# => ["name: Cincinnati Reds venues: Great American Ball Park"]
Notice that when an iterator declares variables, even if there is a variable with the same name outside the block, the scope of the block is respected and the block's variables remain local.
That's some pretty ugly code if you ask me, but it's a place to start.

Match an ID then inject new data

I think I am getting myself massively confused here in Ruby...
I have an array:
array1 = [["4b411f2bf964a52082c125e3", "The Three Pigeons", 51.236318, -0.57055], ["4b444648f964a52049f325e3", "The Royal Oak", 51.23555937678702, -0.5702378403809515], ["4b92c695f964a520aa1a34e3", "Slug And Lettuce", 51.237156, -0.571021], ["4b490136f964a520a56126e3", "The Robin Hood", 51.23603403568268, -0.568686], ["4b425f85f964a52092d225e3", "The Guildford Tup", 51.237734, -0.5703823], ["4b48f87ff964a520096026e3", "The Keep", 51.234704, -0.572574], ["4b426369f964a520e3d225e3", "The Five & Lime", 51.236908, -0.573695], ["4b56243af964a5204f0228e3", "The Albany", 51.23687122552597, -0.5666781994529876], ["4b426047f964a520a4d225e3", "The Kings Head", 51.234176, -0.573656], ["4b4261e4f964a520c6d225e3", "The Live and Let Live", 51.238477, -0.573306], ["4b425ec9f964a52086d225e3", "The Star Inn - Shepherd Neame", 51.23501026190194, -0.5749610066413879], ["4cb995490180721e03e09461", "Prince Albert", 51.242471, -0.572899], ["4e02726dc65b8061424b59f1", "Bar Mambo", 51.236896, -0.577263], ["4b7451e5f964a520fad42de3", "The Rodboro Buildings (Wetherspoon)", 51.236624141592365, -0.5775332450866699], ["4b6de739f964a520769a2ce3", "The White House", 51.23463575311113, -0.5773776769638062], ["4bb504a30ef1c9b6dbc2f412", "The Britannia - Shepherd Neame", 51.233105063438416, -0.5760687589645386], ["4b4447f8f964a5206cf325e3", "The George Abbot", 51.235186599066246, -0.5779409408569336], ["4b894378f964a520e72632e3", "The Boatman", 51.23155028087051, -0.572927], ["4bb475f449bdc9b65bcb0c10", "The Keystone", 51.23437208365849, -0.5779758095741272], ["4ba55291f964a5209afa38e3", "Rogues Bar", 51.23763173808256, -0.5610001087188721], ["4b40ce65f964a5205ebb25e3", "The Drummond", 51.24133950313797, -0.5758380889892578], ["4b48c8a8f964a520cb5626e3", "The Stok", 51.24272843225208, -0.5718989403261525], ["4c4f275651c2c9288af1859f", "The Parkway", 51.248229, -0.569356], ["4b48a60ff964a5208c5126e3", "The King's Head", 51.24666037427897, -0.5728936419289142], ["4b9a86c4f964a520f2bd35e3", "Ye Olde Ship Inn", 51.225673503520696, -0.5796146392822266], ["4c582015a7d976b0130cddee", "Wates House", 51.2420380341127, -0.5908584594726562], ["4b484917f964a520184b26e3", "The Rowbarge", 51.25055105804697, -0.5729025186239382], ["4bd86cb6e914a593c92f53fa", "The Wooden Bridge", 51.248547, -0.58514], ["4bd8b0442e6f0f4754240808", "The Seahorse", 51.218605041503906, -0.569018], ["4bb61c6bef159c74ff6b75f7", "The Astolat Public House", 51.23704061748392, -0.5893993377685547], ["4c978b274f16b71312c2ce3f", "The Queen Victoria", 51.21475338935852, -0.567119], ["4bb0eb08f964a520006a3ce3", "Anchor & Horseshoes", 51.254823, -0.548787], ["4c126e3c82a3c9b60ab0f9f8", "The Garage Tavern", 51.261162, -0.586647], ["4bed4208bac3c9b692fcfde9", "The Cricketers", 51.254246288978116, -0.6047425123927289], ["4b92cb0bf964a520501c34e3", "Horse & Groom", 51.24614672635736, -0.5279016494750977], ["4e8b7820be7b1b0656b1f927", "Apple Tree Pub", 51.2460676, -0.61427766], ["4dc58ce152b1e8f9f7d7378b", "Royal Oak", 51.248792, -0.626987], ["4c1a1c70838020a137aae661", "Withies Inn", 51.21199, -0.621551], ["4baded59f964a52031733be3", "The Jolly Farmer", 51.194106, -0.558244], ["4e21b6f052b1f82ffba120b5", "Compton Royal British Legion", 51.21349872454546, -0.6290990092597657], ["4b646071f964a52052ae2ae3", "The Jolly Farmer", 51.27866916930163, -0.5856227874755859], ["4d987f7961a3a1cd32aace42", "White Hart", 51.25011, -0.636736], ["4c8ccb34509e3704d9533655", "The Harrow Inn", 51.213387, -0.6316709518432617], ["4b71bb30f964a5200b592de3", "Bull's Head", 51.253260091783105, -0.5042177438735962], ["4f63b0b5e4b087553c2ae4fa", "The freeholders", 51.194189, -0.603889], ["4bc762a32f94d13aebd2117f", "The Cricketers", 51.194975, -0.608211], ["4be6c014bcef2d7f476805e5", "Worplesdon Place (Beef Eater Grill)", 51.27501810816803, -0.6078529357910156], ["4dbd63785da3ff58ec6192b1", "Scratchers", 51.19211, -0.60234], ["4e687a6bb3ad5d9197518ed6", "Three Lions - Shepherd Neame", 51.19198564344851, -0.6023865938186646], ["4c714ddcb5a5236acb995252", "The White heart Pub", 51.200254, -0.603593]]
I pass these results to an API that scores them. The result I get back is an array with lots of hashes in them. The Key is the ID from the array1 and the value is the score
array2 = [{"4bed4208bac3c9b692fcfde9"=>743.0}, {"4e21b6f052b1f82ffba120b5"=>789.0}, {"4b646071f964a52052ae2ae3"=>921.0}, {"4bb504a30ef1c9b6dbc2f412"=>99.0}, {"4b426369f964a520e3d225e3"=>80.0}, {"4c4f275651c2c9288af1859f"=>254.0}, {"4b92cb0bf964a520501c34e3"=>468.0}, {"4b425f85f964a52092d225e3"=>27.0}, {"4bd86cb6e914a593c92f53fa"=>512.0}, {"4e687a6bb3ad5d9197518ed6"=>622.0}, {"4b4447f8f964a5206cf325e3"=>73.0}, {"4b425ec9f964a52086d225e3"=>26.0}, {"4b484917f964a520184b26e3"=>328.0}, {"4b426047f964a520a4d225e3"=>37.0}, {"4c978b274f16b71312c2ce3f"=>253.0}, {"4b6de739f964a520769a2ce3"=>81.0}, {"4b48c8a8f964a520cb5626e3"=>167.0}, {"4bb475f449bdc9b65bcb0c10"=>80.0}, {"4c126e3c82a3c9b60ab0f9f8"=>739.0}, {"4bd8b0442e6f0f4754240808"=>210.0}, {"4bb61c6bef159c74ff6b75f7"=>231.0}, {"4b56243af964a5204f0228e3"=>56.0}, {"4b411f2bf964a52082c125e3"=>0.0}, {"4b48a60ff964a5208c5126e3"=>211.0}, {"4baded59f964a52031733be3"=>514.0}, {"4b40ce65f964a5205ebb25e3"=>124.0}, {"4b444648f964a52049f325e3"=>81.0}, {"4bb0eb08f964a520006a3ce3"=>376.0}, {"4f63b0b5e4b087553c2ae4fa"=>586.0}, {"4b9a86c4f964a520f2bd35e3"=>192.0}, {"4cb995490180721e03e09461"=>125.0}, {"4dc58ce152b1e8f9f7d7378b"=>955.0}, {"4b92c695f964a520aa1a34e3"=>20.0}, {"4c582015a7d976b0130cddee"=>484.0}, {"4c8ccb34509e3704d9533655"=>743.0}, {"4b48f87ff964a520096026e3"=>48.0}, {"4c1a1c70838020a137aae661"=>640.0}, {"4b894378f964a520e72632e3"=>55.0}, {"4e8b7820be7b1b0656b1f927"=>666.0}, {"4e02726dc65b8061424b59f1"=>78.0}, {"4b4261e4f964a520c6d225e3"=>57.0}, {"4ba55291f964a5209afa38e3"=>77.0}, {"4c714ddcb5a5236acb995252"=>473.0}, {"4b7451e5f964a520fad42de3"=>80.0}, {"4b490136f964a520a56126e3"=>71.0}, {"4d987f7961a3a1cd32aace42"=>1008.0}, {"4dbd63785da3ff58ec6192b1"=>622.0}, {"4b71bb30f964a5200b592de3"=>640.0}, {"4be6c014bcef2d7f476805e5"=>1016.0}, {"4bc762a32f94d13aebd2117f"=>577.0}]
I would like to end up with a new array that includes the value of the matched key in array 2 to array 1 e.g.
["4c714ddcb5a5236acb995252", "The White heart Pub", 51.200254, -0.603593, 622]
Not every value in array1 will get a score, some will not get anything and as a result they will not be returned in array2 at all. So I need to match them by id("4c714ddcb5a5236acb995252") and check if they are present and then match. the score with the data in array1
Array.assoc is nice for this:
array2.each{|h| array1.assoc(h.keys.first) << h.values.first}
p array1
Since these should be hashes, lets turn them into ones:
h1 = array1.each_with_object({}) { |a, h| h[a.first] = a[1..-1] }
#=> {"4b411f2bf964a52082c125e3"=>["The Three Pigeons", 51.236318, -0.57055], ... }
h2 = array2.inject(:merge)
#=> {"4bed4208bac3c9b692fcfde9"=>743.0, ... }
then we can easily create a final hash:
result = h2.each { |k, v| h1[k] << v }
#=> {"4b411f2bf964a52082c125e3"=>["The Three Pigeons", 51.236318, -0.57055, 0.0], ... }
note that this will break if h2 has a key that h1 doesn't already (or, more specifically, that h1's key's value isn't an array).
If you really want this in the array form you give, you can do:
result = result.map { |k, v| v.unshift(k) }
#=> [["4b411f2bf964a52082c125e3", "The Three Pigeons", 51.236318, -0.57055, 0.0], ... ]
I would use map from Enumerable like this:
array3 = array2.map do |item_from_array2|
id = item_from_array2.keys[0]
item_from_array1 = array1.find { |item| item.include?(id) }
item_from_array1.dup << item_from_array2[id]
end
Here, I enumerate over the items in array2 so that the result only contains items that exist in array2. Then, I get the id and search for the array in array1 that has that id. Then, add the value from array2 to the end of the item found from array1. Finally, map makes an array from every returned value.
As a performance consideration, you may want to create a hash from the first array that you can index by the id because calling array1.find every iteration will be slower than using hash1[id] every iteration.

Resources