Setting hash values from array - ruby

I have a hash:
row = {
'name' => '',
'description' => '',
'auth' => '',
'https' => '',
'cors' => '',
'url' => ''
}
and I also have an array:
["Cat Facts", "Daily cat facts", "No", "Yes", "No", "https://example.com/"]
How can I grab the array elements and set them as values for each key in the hash?

Let's say row is your hash and values is your array
row.keys.zip(values).to_h
=> {"name"=>"Cat Facts", "description"=>"Daily cat facts", "auth"=>"No", "https"=>"Yes", "cors"=>"No", "url"=>"https://example.com/"}
It works if they are in the right order, of course

h = { 'name'=>'',
'description'=>'',
'auth'=>'',
'https'=>'',
'cors'=>'',
'url'=>'' }
arr = ["Cat Facts", "Daily cat facts", "No", "Yes", "No",
"https://example.com/"]
enum = arr.to_enum
#=> #<Enumerator: ["Cat Facts", "Daily cat facts", "No",
# "Yes", "No", "https://example.com/"]:each>
h.transform_values { enum.next }
#=> { "name"=>"Cat Facts",
# "description"=>"Daily cat facts",
# "auth"=>"No",
# "https"=>"Yes",
# "cors"=>"No",
# "url"=>"https://example.com/" }
See Hash#transform_values. Array#each can be used in place of Kernel#to_enum.
If arr can be mutated enum.next can be replaced with arr.shift.

Given the hash and the array:
row = { 'name' => '', 'description' => '', 'auth' => '', 'https' => '', 'cors' => '', 'url' => '' }
val = ["Cat Facts", "Daily cat facts", "No", "Yes", "No", "https://example.com/"]
One option is to use Enumerable#each_with_index while transforming the values of the hash:
row.transform_values!.with_index { |_, i| val[i] }
row
#=> {"name"=>"Cat Facts", "description"=>"Daily cat facts", "auth"=>"No", "https"=>"Yes", "cors"=>"No", "url"=>"https://example.com/"}
The bang ! changes the original Hash.

Related

Pushing objects into a hash inside a loop

I'm trying to achieve the following JSON results:
{
"movie" =>
[{
"title": "Thor",
"year" : 2011,
},
{
"title": "Iron Man",
"year" : 2008,
}],
"tv" =>
[{
"title": "Parks and Recreation"
"year": 2009
},
{
"title": "Friends"
"year": 1994
}]
}
With JavaScript, I would loop through my results and do something like:
results['movie'].push(item);
results['tv'].push(item);
With Ruby code, the farthest I've gone is this:
#results = Hash.new
results['Search'].each do |r|
if r['Type'] == 'movie'
#results['movie'] << {
'title' => r['Title'],
'year' => r['Year']
}
elsif r['Type'] == 'series'
#results['tv'] << {
'title' => r['Title'],
'year' => r['Year']
}
end
end
What am I missing here?
I think you can get what you want by using Enumerable#each_with_object and assigning a default value to the hash.
def group_search_results(items)
results = Hash.new { |hash, key| hash[key] = [] }
items.each_with_object(results) do |item|
results[item['Type']] << {'title' => item['Title'], 'year' => item['Year']}
end
end
describe "search_results" do
it "groups into an object" do
items = [
{'Type' => 'movie', 'Title' => 'Thor', 'Year' => 2011},
{'Type' => 'movie', 'Title' => 'Iron Man', 'Year' => 2008},
{'Type' => 'series', 'Title' => 'Parks and Recreation', 'Year' => 2009},
{'Type' => 'series', 'Title' => 'Friends', 'Year' => 1994},
]
results = group_search_results(items)
expect(results).to eq({
'movie' => [
{'title' => 'Thor', 'year' => 2011},
{'title' => 'Iron Man', 'year' => 2008},
],
'series' => [
{'title' => 'Parks and Recreation', 'year' => 2009},
{'title' => 'Friends', 'year' => 1994},
],
})
end
end
I believe the problem has to do with the initialization of your hash. The movie and tv keys aren't currently an array. You can initialize your hash like this:
#results = { 'movie' => [], 'tv' => [] }
Here's how it looks with the rest of your code:
#results = { 'movie' => [], 'tv' => [] }
results['Search'].each do |r|
if r['Type'] == 'movie'
#results['movie'] << {
'title' => r['Title'],
'year' => r['Year']
}
elsif r['Type'] == 'series'
#results['tv'] << {
'title' => r['Title'],
'year' => r['Year']
}
end
end
results = {
search: {
movie: [
{ title: 'Thor', year: 2011 },
{ title: 'Iron Man', year: 2008 },
],
tv: [
{ title: 'Parks and Recreation', year: 2009 },
{ title: 'Friends', year: 1994 },
]
}
}
#results = Hash.new{|k, v| k[v] = []}
results[:search].each do |type, array|
#results[type].push(*array)
end
results[:search].each_with_object(Hash.new{|k, v| k[v] = []}) do |(type, array), hash|
hash[type].push(*array)
end

Outputting the keys of the max value of a hash within Arrays in Ruby using methods

data = [
"Company one" => {
"number_1" => 46,
"number_2" => 3055,
"country" => "USA"
},
"Company two" => {
"number_1" => 32,
"number_2" => 6610,
"country" => "USA"
},
"Company three" => {
"number_1" => 40,
"number_2" => 9128,
"country" => "USA"
}
]
So I have this array in which I'm trying to get which of the company has the biggest number in 'number_2'. The largest would be Company three with 9128.
So I have this code that puts the largest number which would be 9128
def number(data)
collected_array=[]
data.each do |company_hash|
collected_array = company_hash.map do |k,v|
v["number_2"]
end
end
puts collected_array.max
end
number(data)
But I'm trying to puts the company name with the largest number which would be "Company three". I've tried .keys and other ways but it gives me error.
I've tried this way:
def number(data)
collected_array=[]
data.each do |company_hash|
collected_array = company_hash.map do |k,v|
v["number_2"]
k
end
end
puts collected_array.max
end
number(data)
but it gives me "Company two" rather than "Company three" which would be the company with the highest number
As stated by #Cary, it can be simplified accessing the first element on data, and there using max_by, on the hash local variable available within the block checking the number_2 key value.
As the result is an Array containing two elements, the first one is the company name, the second and last one, the hash containing its data:
data = [
"Company one" => {
"number_1" => 46,
"number_2" => 3055,
"country" => "USA"
},
"Company two" => {
"number_1" => 32,
"number_2" => 6610,
"country" => "USA"
},
"Company three" => {
"number_1" => 40,
"number_2" => 9128,
"country" => "USA"
}
]
max_company = data.first.max_by { |_, h| h['number_2'] }
p max_company.first # "Company three"
p max_company.last['number_2'] # 9128

How do you check if an array element is empty or not in Ruby?

How do you check if an array element is empty or not in Ruby?
passwd.where { user =~ /.*/ }.uids
=> ["0", "108", "109", "110", "111", "112", "994", "995", "1001", "1002", "", "65534"]
To check if the array has an empty element, one of the many ways to do it is:
arr.any?(&:blank?)
Not sure what you want to do with it, but there are quite a few ways to skin this cat. More info would help narrow it down some...
["0", "108", "109", "110", "111", "112", "994", "995", "1001", "1002", "", "65534"].map { |v| v.empty? }
=> [false, false, false, false, false, false, false, false, false, false, true, false]
["0", "108", "109", "110", "111", "112", "994", "995", "1001", "1002", "", "65534"].each_with_index { |v,i| puts i if v.empty? }
10
arr = [ "0", "108", "", [], {}, nil, 2..1, 109, 3.2, :'' ]
arr.select { |e| e.respond_to?(:empty?) && e.empty? }
#=> ["", [], {}, :""]
Assuming your array is an array of strings
arr = [ "name", "address", "phone", "city", "country", "occupation"]
if arr.empty?
p "Array is empty"
else
p "Array has values inside"
These test for emptiness:
'foo'.empty? # => false
''.empty? # => true
[1].empty? # => false
[].empty? # => true
{a:1}.empty? # => false
{}.empty? # => true
Testing to see if an element in an array is empty would use a similar test:
['foo', '', [], {}].select { |i| i.empty? } # => ["", [], {}]
['foo', '', [], {}].reject { |i| i.empty? } # => ["foo"]
or, using shorthand:
['foo', '', [], {}].select(&:empty?) # => ["", [], {}]
['foo', '', [], {}].reject(&:empty?) # => ["foo"]

Convert array of key value object to object of the key values (ruby)

I have a list of objects that have key attribute and value attribute.
I would like to convert it to an object that contains attributes named as keys with the values.
Example will make it clearer...
This
[{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}]
Should become like this:
{
:key1 => "value1"
:key2 => "value2"
}
I'm sure there is one line to make it happen
Thanks
Using Hash::[], Array#map:
a = [{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}]
Hash[a.map { |h| [h[:key], h[:value]] }]
# => {"key1"=>"value1", "key2"=>"value2"}
Hash[a.map { |h| h.values_at(:key, :value) }]
# => {"key1"=>"value1", "key2"=>"value2"}
Hash[a.map { |h| [h[:key].to_sym, h[:value]] }]
# => {:key1=>"value1", :key2=>"value2"}
a.each_with_object({}) {|h,g| g.update({h[:key].to_sym => h[:value]}) }
# => {:key1=>"value1", :key2=>"value2"}
Hash[array.map(&:values)]
#=> {"key1"=>"value1", "key2"=>"value2"}
Just to promote the to_h a bit:
[{
:key => "key1",
:value => "value1"
}, {
:key => "key2",
:value => "value2"
}].map(&:values).map{|k,v| [k.to_sym,v]}.to_h
# => {:key1=>"value1", :key2=>"value2"}

Group by and format array of hash values in ruby

Hey I have an array of hash values as follows.
[{"group" => "1", "message" => "hey", "weight" => 1}, {"group" => "1", "message"
=> "hey1", "weight" => 2}, {"group" => "2", "message" => "hey3", "weight" => 4}]
I want to group_by group and format it so that I get the following:
[{"group" => 1, "messages" => {"hey","hey1"}, "weights" => {1,2}}, {"group" => 2,
"messages" => {"hey3"}, "weights" => {4}}]
Is there a nice ruby way to achieve this?
Edit: Now I have:
[
{"group" => "1", "message" => {"hey" => "1"}},
{"group" => "1", "message" => {"hey1" => "2"}}
]
I'd like to have
{"group" => "1", "messages" => {"hey1" => "1", "hey2" => "2"} }
Based on your revised question:
groups = [
{"group" => "1", "message" => {"hey" => "1"}},
{"group" => "1", "message" => {"hey1" => "2"}}
]
merged = groups.inject do |h1,h2|
h1.merge(h2) do |k,v1,v2|
if v1==v2
v1
elsif v1.is_a?(Hash) && v2.is_a?(Hash)
v1.merge(v2)
else
[*v1,*v2]
end
end
end
p merged
#=> {"group"=>"1", "message"=>{"hey"=>"1", "hey1"=>"2"}}
I think the output you want is:
[{"messages"=>["hey", "hey1"], "weights"=>[1, 2], "group"=>"1"}, {"messages"=>["hey3"], "weights"=>[4], "group"=>"2"}]
If this is the case, this code does what you want:
h.group_by { |item| item["group"] }.values.map do |item|
item.inject({"messages" => [], "weights" => []}) do |result, subitem|
result["group"] = subitem["group"]
result["messages"] << subitem["message"]
result["weights"] << subitem["weight"]
result
end
end
You should be able to improve it knowing more about your specific problem, but it should be a good starting point.

Resources