ruby hash check if value exists - ruby

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

Related

Grouping individuals by hash values in an array of hashes from user input and outputting names in Ruby

I have the below data structure in Ruby:
people = [
{ "name" => "John", "hobby" => "tennis", "food" => "pizza" },
{ "name" => "Joseph", "hobby" => "tennis", "food" => "burgers" },
{ "name" => "Lauren", "hobby" => "board games", "food" => "salads" }
{ "name" => "Amir", "hobby" => "cycling", "food" => "burgers" },
{ "name" => "Mary", "hobby" => "tennis", "food" => "salads" },
{ "name" => "Karen", "hobby" => "board games", "food" => "pie" },
{ "name" => "Will", "hobby" => "cycling", "food" => "pizza" },
]
I need to write a program that will take in user input - either "hobby" or "food" and will then puts out a list of people grouped under subheadings for each hobby or food.
e.g. user inputs 'hobby' and a list is puts'ed to the console similar to the below:
tennis
John
Joseph
Mary
board games
Lauren
Karen
cycling
Amir
Will
So far I have got as far as being able to generate a new array that has the hobbies and the names, however they are seperate and I'm not sure if it's the best way of going around getting the category name with a list of people underneath... also there are a few nil values being pulled out too e.g. below:
puts "Enter what category to search"
category = gets.chomp
grouped_data = people.group_by { |x| x[category] }
new_array = []
grouped_data.each { |n| new_array.push n[0] }
grouped_data.flatten.flatten.each { |n| new_array.push n["name"] }
p new_array
With input "hobby" gives me an array:
["tennis", "board games", "cycling", nil, "John", "Joseph", "Mary", nil, "Lauren", "Karen", nil, "Amir", "Will"]
Am I on the right track? Is there another avenue worth exploring?
Thanks! Hope this has been laid out alright as it's first time posting on SA.
I think you are on the right track by using Enumerable#group_by since it gets you a hash where the keys are the "category" and the values are an array of "persons" that fit that "category". What I think you want to do next is use Hash#transform_values along with Array#map to map each person into just thier name.
people = [
{ "name" => "John", "hobby" => "tennis", "food" => "pizza" },
{ "name" => "Joseph", "hobby" => "tennis", "food" => "burgers" },
{ "name" => "Lauren", "hobby" => "board games", "food" => "salads" } ,
{ "name" => "Amir", "hobby" => "cycling", "food" => "burgers" },
{ "name" => "Mary", "hobby" => "tennis", "food" => "salads" },
{ "name" => "Karen", "hobby" => "board games", "food" => "pie" },
{ "name" => "Will", "hobby" => "cycling", "food" => "pizza" },
]
by_category = people.group_by {|category| category["hobby"]}
.transform_values {|value| value.map{ |person| person["name"]}}
p by_category
Which produces:
{"tennis"=>["John", "Joseph", "Mary"], "board games"=>["Lauren", "Karen"], "cycling"=>["Amir", "Will"]}
Let's consider what each step of your code returns. Assuming category is 'hobby'.
grouped_data = people.group_by { |x| x[category] }
# => {"tennis"=>[{"name"=>"John", "hobby"=>"tennis", "food"=>"pizza"},
# {"name"=>"Joseph", "hobby"=>"tennis", "ood"=>"burgers"},
# {"name"=>"Mary", "hobby"=>"tennis", "food"=>"salads"}],
# "board games"=>[{"name"=>"Lauren", "hobby"=>"board games", "food"=>"salads"},
# {"name"=>"Karen", "hobby"=>"board games", "food"=>"pie"}],
# "cycling"=>[{"name"=>"Amir", "hobby"=>"cycling", "food"=>"burgers"},
# {"name"=>"Will", "hobby"=>"cycling", "food"=>"pizza"}]}
Now:
new_array = []
grouped_data.each { |n| new_array.push n[0] }
new_array
#
=> ["tennis", "board games", "cycling"]
Then:
grouped_data.flatten.flatten.each { |n| new_array.push n["name"] }
new_array
# => ["tennis", "board games", "cycling", nil, "John", "Joseph", "Mary", nil, "Lauren", "Karen", nil, "Amir", "Will"]
If we look at just:
grouped_data.flatten.flatten
# => ["tennis",
# {"name"=>"John", "hobby"=>"tennis", "food"=>"pizza"},
# {"name"=>"Joseph", "hobby"=>"tennis", "food"=>"burgers"},
# {"name"=>"Mary", "hobby"=>"tennis", "food"=>"salads"},
# "board games",
# {"name"=>"Lauren", "hobby"=>"board games", "food"=>"salads"},
# {"name"=>"Karen", "hobby"=>"board games", "food"=>"pie"},
# "cycling", {"name"=>"Amir", "hobby"=>"cycling",
# "food"=>"burgers"}, {"name"=>"Will", "hobby"=>"cycling",
# "food"=>"pizza"}]
This was not a particularly useful data structure to iterate over.
You were on the right track with #group_by and the resulting data structure you got, you just needed to transform the values from an array of hashes into an array of names.
Alternatively...
A little more directly, grouping by hobby without creating unnecessary intermediate objects.
by_hobbies = people.each_with_object({}) do |person, hsh|
hobby = person["hobby"]
hsh[hobby] ||= []
hsh[hobby] << person["name"]
end
p by_hobbies
Output:
{"tennis"=>["John", "Joseph", "Mary"], "board games"=>["Lauren", "Karen"], "cycling"=>["Amir", "Will"]}

conditional deep merge an array of hashes in ruby

I have two data structures that I would like to merge together - as I understand this is called a 'deep merge'.
It should follow the same logic as Rails' deep merge, except my requirement differs in that values are only overwritten on the target hash if they match certain conditions.
As an example, given the following two data structures:
hash1 = {
"data": [
{"id": "1", "type": "foo", created_at: "<IGNORE>" },
{"id": "2", "type": "bar", created_at: "<IGNORE>" }
],
meta: {
page: 1
}
}
hash2 = {
"data": [
{"id": "1", "type": "baz", created_at: "01.01.2022", name: 'thing' },
{"id": "2", "type": "qux", created_at: "02.01.2022" }
],
meta: {
page: 1
}
}
I would like to achieve the following output:
irb(main):001:0> hash1.deep_merge(hash2)
=> {
"data": [
{"id": "1", "type": "baz", created_at: "<IGNORE>", name: 'thing' },
{"id": "2", "type": "qux", created_at: "<IGNORE>" }
],
meta: {
page: 1
}
}
In hash1, the values for created_at contain a tag <IGNORE> that should stipulate that the corresponding value from hash2 should not be merged. All the other keys and values should merge as it would if I was to use Rails' deep_merge.
Disclaimer: You didn't say what the conditions are, even so I'll help you transform this input into this output, it would be interesting to edit your question later and say the conditions.
i don't have many knowledge in ruby but i created a simple algorithm for merge two hash structures without duplicates and keep data type of key, it's not
the better algorithm or solution but i think this implemetation help to your a find other better solution for resolver your problem
Complexity O(n)
Join the hashes and transform the keys into a string
result = hash1.merge(hash2).transform_keys(&:to_s)
save meta information
meta = hash1[:meta]
convert array of symbols to array of strings
`result = result["data"].map do |res|
{
'id' => res[:id].to_s,
'type' => res[:type].to_s,
'created_at' => res[:created_at].to_s,
'name' => res[:name].to_s
}
end
`
if the hash does not have the key name remove it
`
result =
result.map {
|res| res["name" == ""] ? {
'id' => res["id"],
'type' => res["type"],
'created_at' => res["created_at"]
} : res
}
`
Build new hash :D
final_result = {"data" => result, meta: meta}
output result

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: including a hash inside another hash

I have the following hash:
EMAIL_PWD_HASH = Hash.new
EMAIL_PWD_HASH[ "email" ] = { "label" => EMAIL_STR, "type" => "email_field" }
EMAIL_PWD_HASH[ "password" ] = { "label" => PWD_STR, "type" => "password_field" }
and the following hash:
NEW_USER_HASH = Hash.new
NEW_USER_HASH[ "first" ] = { "label" => FIRST_STR, "type" => "text_field" }
NEW_USER_HASH[ "last" ] = { "label" => LAST_STR, "type" => "text_field" }
NEW_USER_HASH[ "title" ] = { "label" => TITLE_STR, "type" => "text_field" }
NEW_USER_HASH[ "bio" ] = { "label" => BIO_STR, "type" => "text_field" }
I would like to add email and password to NEW_USER_HASH after last and before bio. What is the syntax for adding EMAIL_PWD_HASH (the order is important)?
NEW_USER_HASH.merge!(EMAIL_PAD_HASH)
Note also that hashes in ruby are not ordered.
I don't know how to do what you asked, and I doubt it's possible, but here's a quick and dirty way to do what you need:
NEW_USER_HASH['email'] = EMAIL_PWD_HASH['email']
NEW_USER_HASH['password'] = EMAIL_PWD_HASH['password']
NEW_USER_HASH['bio'] = NEW_USER_HASH.delete('bio') # deletes bio and reinsert in the end
email and password are now after last and before bio, as you asked. :)

Resources