Get the value of a key of each hash inside an array - ruby

I have got an array of hashes, for example:
[{"id" => "1", "name" => "Name 1"},
{"id" => "2", "name" => "Name 2"},
{"id" => "3", "name" => "Name 3"}]
I would like to get the value of the key "name" for each hash, similar to this:
["Name 1", "Name 2", "Name 3"]
I looked around for quite a while but couldn't find the answer I was looking for.

It's simplest to use Enumerable#map for this purpose:
array = [{"id" => "1", "name" => "Name 1"}, {"id" => "2", "name" => "Name 2"}, {"id" => "3", "name" => "Name 3"}]
array.map { |hash| hash['name'] }
# => ["Name 1", "Name 2", "Name 3"]

Related

Creating a hash inside an array that contains hashes

Let me preface this by saying I am just starting to learn ruby...
I have any array that is made of hashes, and arrays nested within each other. It looks like this:
people =
[
{
"John Doe" => {
"phone" => "555-555-555",
"company" => "Company name",
"children" => [
"John",
"Jane",
"Annamarie"
]
},
"Jane Smith" => {
"phone" => "555-555-5555",
"company" => "company name",
"children" => [
"Steven"
]
}
}
]
How would I go about adding a new hash where the name of the person acts as a key, and the new hash is the value? E.g. I want to add "spouse" so the hash would look like this:
people =
[
{
"John Doe" => {
"phone" => "555-555-555",
"company" => "Company name",
"children" => [
"John",
"Jane",
"Annamarie"
],
"spouse" => "Jane Doe"
},
"Jane Smith" => {
"phone" => "555-555-5555",
"company" => "company name",
"children" => [
"Steven"
],
"spouse" => "John Smith"
}
}
]
You can use select to get the hash with "John Doe" as the key...
search_user = "John Doe"
person = people.select{|p| p.has_key?(search_user)}.first
person[search_user]['spouse'] = "Jane Doe" if person
The reason for if person on the last line is to handle the case that no "John Doe" was found.

How do I convert an Array with a JSON string into a JSON object (ruby)

I have an Array whose content is as follow:
[
[0] {
"name" => “Mark”,
"id" => “01”,
"description" => “User”,
},
[1] {
"name" => “John”,
"id" => “02”,
"description" => “Developer”,
}
]
Note: right now each item of the Array is a Hash (not a string). That is to say that if I do puts myarray[0].class I get hash in return.
I would like to be able to create an object that I can reference as object[i].field.
For example I'd like to be able to get "Mark" by calling object[0].name or get "Developer" by calling object[1].description.
Is this possible? I have tried to leverage the .to_json method against my array but it doesn't quite give me what I need.
Thanks.
You can do use Struct to meet your need.
array = [
{
"name" => "Mark",
"id" => "01",
"description" => "User",
},
{
"name" => "John",
"id" => "02",
"description" => "Developer",
}
]
Customer = Struct.new(:name, :id, :description)
array_of_customers = array.map { |hash| Customer.new(*hash.values) }
array_of_customers[1].name # => "John"
array_of_customers[1].description # => "Developer"

ruby hash check if value exists

Must be an easy question.. but I can't seem to find the answer.
I'm trying to check if a value exists for a specific key within hash.
hash = {{"name" => "John", "Loc" => "US", "fname" => "John Doe"},
{"name" => "Eve", "Loc" => "UK", "fname" => "John Eve"}}
Currently I am looping through hash, to check for if h["name"] = "John"...
I was looking to see if a .include or .has_value? type of approach is available. I read the documentation on hash and a book I have on hand but couldn't find it.
I thought something like if hash["name"].has_value?("John") be most useful than looping through hash. Thanks in advance for the help!
First of all our hash is not a valid hash. I suppose you want to have an array of hashes like this
array = [
{ "name" => "John", "Loc" => "US", "fname" => "John Doe" },
{ "name" => "Eve", "Loc" => "UK", "fname" => "John Eve" }
]
then you can do something like this:
array.select { |hash| hash['name'] == 'John' }
# => returns [{"name" => "John", "Loc" => "US", "fname" => "John Doe"}]
array.any? { |hash| hash['name'] == 'John' }
# => true

The $project operation fails to work with Mongoid aggregate method when used after $group

I have a simple dataset in a MongoDB (version 2.2.2):
{
"_id": "527d60865593622ba17643e6",
"siteid": "100",
"date": 1383940800,
"visits": 1
},
{
"_id": "527d60865593622ba17643e7",
"siteid": "200",
"date": 1383940801,
"visits": 1
},
{
"_id": "527d60865593622ba17643e8",
"siteid": "200",
"date": 1383940802,
"visits": 1
}
I have a Mongoid (version 3.0.1) collection where I'm trying to use the aggregate method:
query = {
"$project" => { _id: 0 },
"$match" => {"$and" => [{:date=>{"$gte"=>1383940800}}, {:date=>{"$lt"=>1384027200}}]},
"$group" => {"_id" => "$siteid", "visits" => {"$sum" => "$visits"}},
"$project" => { "siteid" => "$_id" }
}
result = #object.collection.aggregate(query)
The result that I get back is this:
[{"_id"=>200, "visits"=>2}, {"_id"=>100, "visits"=>1}]
What I'd like the result to be is this:
[{"siteid"=>200, "visits"=>2}, {"siteid"=>100, "visits"=>1}]
I thought the last $project operation would do this for me but it seems to be completely ignored. Any suggestions?
The argument to the aggregate method is a pipeline which is an array of hashes where each hash is a stage.
Your example query is a hash with values that are hashes; too bad that it reads well, but this obscures the misuse.
Unfortunately, Moped somehow allows this misuse even though the mongo shell catches it and returns the server error message
"exception: A pipeline stage specification object must contain exactly one field."
I hope that you like the following, I think that it is what you want.
test/unit/visit_test.rb
require 'test_helper'
require 'json'
class VisitTest < ActiveSupport::TestCase
def setup
Visit.delete_all
puts
end
test "0. mongoid version" do
puts "Mongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}"
end
test "project after group" do
data = JSON.parse(<<-EOD
[
{"_id": "527d60865593622ba17643e6", "siteid": "100", "date": 1383940800, "visits": 1},
{"_id": "527d60865593622ba17643e7", "siteid": "200", "date": 1383940801, "visits": 1},
{"_id": "527d60865593622ba17643e8", "siteid": "200", "date": 1383940802, "visits": 1}
]
EOD
)
Visit.create(data)
assert_equal 3, Visit.count
pipeline = [
{"$match" => {"$and" => [{:date => {"$gte" => 1383940800}}, {:date => {"$lt" => 1384027200}}]}},
{"$group" => {"_id" => "$siteid", "visits" => {"$sum" => "$visits"}}},
{"$project" => {"_id" => 0, "siteid" => "$_id", "visits" => 1}}
]
p Visit.collection.aggregate(pipeline)
end
end
rake test
Run options:
# Running tests:
[1/2] VisitTest#test_0._mongoid_version
Mongoid::VERSION:3.1.5
Moped::VERSION:1.5.1
[2/2] VisitTest#test_project_after_group
[{"visits"=>2, "siteid"=>"200"}, {"visits"=>1, "siteid"=>"100"}]
Finished tests in 0.038172s, 52.3944 tests/s, 26.1972 assertions/s.
2 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Merging records in JSON with Ruby

I have two json files that I'm trying to merge. The JSONs have different formatting (see below). I'd like to merge records, so [0] from file one and [0] from file two would become one record [0] in the new merged file.
The first JSON (file_a.json), appears like so:
{
"query": {
"count": 4,
"created": "2012-11-21T23:07:00Z",
"lang": "en-US",
"results": {
"quote": [
{
"Name": "Bill",
"Age": "46",
"Number": "3.55"
},
{
"Name": "Jane",
"Age": "33",
"Number": nil
},
{
"Name": "Jack",
"Age": "55",
"Number": nil
},
{
"Name": "Xavier",
"Age": nil,
"Number": "153353535"
}
]
}
}
}
The second JSON (file_b.json) appears like so:
[
{
"Number2": 25253,
"Number3": 435574,
"NAME": "Bill"
},
{
"Number2": 345353,
"Number3": 5566,
"NAME": "Jane"
},
{
"Number2": 56756,
"Number3": 232435,
"NAME": "Jack"
},
{
"Number2": 7457,
"Number3": 45425,
"NAME": "Xavier"
}
]
None of the keys are the same in both JSONs (well, actually "Name" is a key in both, but in the first the key is "Name" and in the second its "NAME" - just so I can check that the merge works correctly - so I want "Name" and "NAME" in the final JSON), the first record in the first file matches with the first record in the second file, and so on.
So far, I tried merging like this:
merged = %w[a b].inject([]) { |m,f| m << JSON.parse(File.read("file_#{f}.json")) }.flatten
But this of course merged them, but not how I wanted them merged (they are merged sucessively, and because of the different formatting, it gets quite ugly).
I also tried merging like this:
a = JSON.parse(File.read("file_a.json"))
b = JSON.parse(File.read("file_b.json"))
merged = a.zip(b)
Came closer but still not correct and the formatting was still horrendous.
In the end, what I want is this (formatting of second JSON - headers from first JSON can be junked):
[
{
"Name": "Bill",
"Age": 46,
"Number": 3.55,
"Number2": 25253,
"Number3": 435574,
"NAME": "Bill"
},
{
"Name": "Jane",
"Age": 33,
"Number": nil,
"Number2": 345353,
"Number3": 5566,
"NAME": "Jane"
},
{
"Name": "Jack",
"Age": 55,
"Number": nil,
"Number2": 56756,
"Number3": 232435,
"NAME": "Jack"
},
{
"Name": "Xavier",
"Age": nil,
"Number": 153353535,
"Number2": 7457,
"Number3": 45425,
"NAME": "Xavier"
}
]
Any help is appreciated. Thanks a lot.
Hеllo, seems format changed from last time :)
UPDATE: more readable version that also convert corresponding values to integers/floats:
require 'json'
require 'ap'
a = JSON.parse(File.read('./a.json'))['query']['results']['quote'] rescue []
b = JSON.parse(File.read('./b.json'))
final = []
a.each_with_index do |ah,i|
unless bh = b[i]
bh = {}
puts "seems b has no #{i} key, merging skipped"
end
final << ah.merge(bh).inject({}) do |f, (k,v)|
if v.is_a?(String)
if v =~ /\A\d+\.\d+\Z/
v = v.to_f
elsif v =~ /\A\d+\Z/
v = v.to_i
end
end
f.update k => v
end
end
ap final
will display:
[
[0] {
"Name" => "Bill",
"Age" => 46,
"Number" => 3.55,
"Number2" => 25253,
"Number3" => 435574,
"NAME" => "Bill"
},
[1] {
"Name" => "Jane",
"Age" => 33,
"Number" => nil,
"Number2" => 345353,
"Number3" => 5566,
"NAME" => "Jane"
},
[2] {
"Name" => "Jack",
"Age" => 55,
"Number" => nil,
"Number2" => 56756,
"Number3" => 232435,
"NAME" => "Jack"
},
[3] {
"Name" => "Xavier",
"Age" => nil,
"Number" => 153353535,
"Number2" => 7457,
"Number3" => 45425,
"NAME" => "Xavier"
}
]
Here is a working demo
Btw, your json is a bit wrong in both files.
See the fixed versions here and here

Resources