Array of Hashes to Hash

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



Leave a reply



Submit