Array of hashes to hash
You may use
a.reduce Hash.new, :merge
which directly yields
{:a=>:b, :c=>:d}
Note that in case of collisions the order is important. Latter hashes override previous mappings, see e.g.:
[{a: :b}, {c: :d}, {e: :f, a: :g}].reduce Hash.new, :merge # {:a=>:g, :c=>:d, :e=>:f}
Convert array of hashes to single hash with values as keys
This should do what you want
countries.each_with_object({}) { |country, h| h[country[:country].to_sym] = country[:cost] }
=> {:england=>12.34, :scotland=>56.78}
Convert array-of-hashes to a hash-of-hashes, indexed by an attribute of the hashes
Ruby <= 2.0
> Hash[api_response.map { |r| [r[:id], r] }]
#=> {1=>{:id=>1, :foo=>"bar"}, 2=>{:id=>2, :foo=>"another bar"}}
However, Hash::[] is pretty ugly and breaks the usual left-to-right OOP flow. That's why Facets proposed Enumerable#mash:
> require 'facets'
> api_response.mash { |r| [r[:id], r] }
#=> {1=>{:id=>1, :foo=>"bar"}, 2=>{:id=>2, :foo=>"another bar"}}
This basic abstraction (convert enumerables to hashes) was asked to be included in Ruby long ago, alas, without luck.
Note that your use case is covered by Active Support: Enumerable#index_by
Ruby >= 2.1
[UPDATE] Still no love for Enumerable#mash
, but now we have Array#to_h. It creates an intermediate array, but it's better than nothing:
> object = api_response.map { |r| [r[:id], r] }.to_h
Ruby Array of hashes to a Hash
array.each_with_object({}){|e, h| e = e.dup; h[e.delete(:a)] = e}
# => {123=>{:b=>"foo", :c=>"bar"}, 456=>{:b=>"baz", :c=>"qux"}}
If you don't care about side effects:
array.each_with_object({}){|e, h| h[e.delete(:a)] = e}
# => {123=>{:b=>"foo", :c=>"bar"}, 456=>{:b=>"baz", :c=>"qux"}}
Convert hash to array of hashes
Leveraging Array#transpose and Array#to_h
keys = list.keys
list.values.transpose.map { |v| keys.zip(v).to_h }
Ruby problem with returning hash value from an array of hashes
After reading your edited question, I see that there are a few conditions that weren't met with previous answers. I also see the main flaw in your code. Let's start with the flaw:
Your code seems a little overly complicated but it should work just fine if you make this one small change to the 5th line of the following section;
def find_favorite(array_of_hash_objects)
array_of_hash_objects.each do | hash |
hash.each do |key, val|
if key == :is_my_favorite? && val == true
return hash
end
end
end
return nil
end
Notice that I prepended the line with return
. Your problem was that you were iterating through the array just fine but there was no container or method being initiated in order to store or return those results. Your second to last line was telling the method to return nil no matter what the results of the iteration were.
Now for my proposed solution:
I see now that your desired output should either be the single hash containing the true
value or should be nil
as opposed to the arrays resulting from the solutions mentioned above. I would probably do something like this;
def find_favorite(input)
output = nil
input.each{|h| h[:is_my_favorite?] ? output = h : nil}
output
end
arr_1 = [{ name: 'Ruby', is_my_favorite?: true }, { name: 'JavaScript', is_my_favorite?: false }, { name: 'HTML', is_my_favorite?: false }]
arr_2 = [{ name: 'Ruby', is_my_favorite?: false }, { name: 'JavaScript', is_my_favorite?: false }, { name: 'HTML', is_my_favorite?: false }]
find_favorite(arr_1) #=> {:name=>"Ruby", :is_my_favorite?=>true}
find_favorite(arr_2) #=> nil
Within the method definition, a container (output
) is first defined with a default value of nil
. We then iterate through the array and fill output
with the hash containing a true value. Otherwise output
returns the default value.
NOTE: You could optionally delete == true ?
from the block but seeing as how I don't know how the original array is being created, I prefer to leave it in there to expressly communicate exactly what I'm looking for in a very human readable way. That's just my personal preference.
Perl, loop through array of hashes and print a specific hash element based on criteria
Let's start by avoiding needless copies of hashes and arrays. We're also going to use better variable names than AoH
, href
and key
.
my $school = decode_json($json);
my $depts = $school->{grade3}{departments};
Now we want the departments that have the value of $dept_name
for name. grep
is a good tool for filtering.
my $dept_name = 'class1';
my @matching_depts = grep { $_->{name} eq $dept_name } @$depts;
Then, it's just a question of iterating over the matching departments, and printing the desired values.
for my $dept (@matching_depts) {
say $dept->{allowedsubjects};
}
Except not quite. That prints
<-- Blank line
general
biology
physics
chemistry
Fix:
for my $dept (@matching_depts) {
say substr($dept->{allowedsubjects}, 1);
}
Alternative fix:
for my $dept (@matching_depts) {
my @subjects = grep { $_ ne "" } split /\n/, $dept->{allowedsubjects};
for my $subject (@subjects) {
say $subject;
}
}
How to separate an array of hashes into different arrays if a key is equal?
Given:
tst=[
{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0},
{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}
]
You can use .group_by to get a hash of elements by key. In this case, use the key ["beneficiary_document"]
passed to the block and you will get a hash of arrays by that key -- two in this case.
You can do:
tst.group_by { |h| h["beneficiary_document"] }
# {"43991028"=>[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0}, {"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0}], "71730550"=>[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84}, {"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}]}
To see it pretty printed:
require "pp"
PP.pp(tst.group_by {|h| h["beneficiary_document"] },$>,120)
{"43991028"=>
[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>5.0},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"43991028", "calification_by_qualifier"=>0.0}],
"71730550"=>
[{"user_id"=>2, "user_name"=>"Pepo", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.84},
{"user_id"=>3, "user_name"=>"Carlos", "beneficiary_document"=>"71730550", "calification_by_qualifier"=>3.4}]}
You can also achieve the same result with a hash that returns an array as a default procedure, then call .map
over tst
and push the hash into the array by that key:
h=Hash.new { |h,k| h[k]=[] }
tst.map { |eh| h[eh["beneficiary_document"]].push(eh) }
Or, combine that into a single statement:
tst.each_with_object(Hash.new { |h,k| h[k]=[] }) { |g,h|
h[g["beneficiary_document"]].push(g)}
All three methods create identical hashes. The first, .group_by
, is the easiest.
How to iterate over an array of hashes in Ruby and return all of the values of a specific key in a string
You can use Enumerable#map for this:
p foods.map { |f| f[:name] }
The code you tried to use did not produce any output or create any objects, and it was not necessary to use a second loop to access a single element of a hash.
Related Topics
Rails Unable to Convert Unpermitted Parameters to Hash
How to Add to a Serialized Array
Combine Array of Array into All Possible Combinations, Forward Only, in Ruby
How to Enable Tls V1.2 in Ruby? If So, How
How to Easily Parse a Url with Parameters in a Rails Test
How to Ftp in Ruby Without First Saving the Text File
How to Test Exception Raising in Rails/Rspec
How to Set Private Instance Variable Used Within a Method Test
Rails 3.1 Absolute Url to an Image
How to Compile Ruby to Byte Code as with Python
How to Elegantly Rename All Keys in a Hash in Ruby
Override Rails Helpers with Access to Original