Array of hashes

I have an array of hashes like this:
a=Array.new()
a.push({:name=>“mario”,:value=>“xxx”})
a.push({:name=>“pedro”,:value=>“lsss”})

and I would like to get a value of the array knowing the :name by doing
something like:
a.each {|h|
if h[:name]==“mario” then value=h[:value]
}

but just in one line, is that possible?

On Wed, Oct 12, 2011 at 1:07 AM, Mario R. [email protected] wrote:

and I would like to get a value of the array knowing the :name by doing

a.find{|x| x[:name]==“pedro”}[:value]
#=> “lsss”

but why not directly use a hash, eg,

h={}
#=> {}
h[“mario”]=“xxx”
#=> “xxx”
h[“pedro”]=“lsss”
#=> “lsss”

h[“pedro”]
#=> “lsss”

kind regards -botp

Thanks!!!
Yep I know that a hash of hashes would be the best but I cannot do that
since the object I’m accessing is not mine

botp wrote in post #1026114:

On Wed, Oct 12, 2011 at 1:07 AM, Mario R. [email protected] wrote:

and I would like to get a value of the array knowing the :name by doing

On Tue, Oct 11, 2011 at 7:44 PM, botp [email protected] wrote:

On Wed, Oct 12, 2011 at 1:07 AM, Mario R. [email protected] wrote:

and I would like to get a value of the array knowing the :name by doing

a.find{|x| x[:name]==“pedro”}[:value]
#=> “lsss”

I tried this also, but stopped when I figured out that if there is no
match for the name, this will cause an exception… I did not
see an elegant solution for that case, with the data structure
that the OP proposes.

$ irb
001:0> a = [{:name => “pedro”, :value => “Isss”}]
=> [{:name=>“pedro”, :value=>“Isss”}]
002:0> a.find{|x| x[:name]==“pedro”}[:value]
=> “Isss”
003:0> a.find{|x| x[:name]==“mario”}[:value]
NoMethodError: undefined method []' for nil:NilClass from (irb):3 from /home/peterv/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in

h[“pedro”]
#=> “lsss”

I agree.

A general question I have is: are there hashes or arrays in Ruby
that offer a logarithmic look-up cost (e.g. implemented with a
btree, like an indexed column on a database). That would make
it really useful to make a better implementation (like you propose)
where you can look-up directly, based on the :name.

Thx,

Peter

Is this what you’re looking for?

a=Array.new()
a.push({:name=>“mario”,:value=>“xxx”})
a.push({:name=>“pedro”,:value=>“lsss”})
a.each {|h| value=h[:value] if h[:name]==“mario” }

=> [{:name=>“mario”, :value=>“xxx”}, {:name=>“pedro”, :value=>“lsss”}]

Peter V. wrote in post #1026119:

002:0> a.find{|x| x[:name]==“pedro”}[:value]
=> “Isss”
003:0> a.find{|x| x[:name]==“mario”}[:value]
NoMethodError: undefined method `[]’ for nil:NilClass

That’s the nil chaining problem. I usually just write something like

res = if val = a.find{|x| x[:name]==“mario”}
v[:value]
end

There is also:

res = a.find{|x| x[:name]==“mario”}[:value] rescue nil

although that might mask other exceptions that you don’t want hidden.

Various additions to Object have been proposed to make the it
unnecessary to guard against nils in chained methods. For example see
number 9 here:

Something similar found its way into Rails 2.3:

http://ozmm.org/posts/try.html

(Instead of just swallowing nils, it checks for the existence of a
method before calling it)

A general question I have is: are there hashes or arrays in Ruby
that offer a logarithmic look-up cost (e.g. implemented with a
btree, like an indexed column on a database).

Hashes are dynamically sized and will give you logarithmic lookup cost.
There are third-party libraries for trees; the main reason for using a
tree instead is so that you can insert nodes at particular places and
retrieve them from the same place.

On Tue, Oct 11, 2011 at 7:07 PM, Mario R. [email protected] wrote:

but just in one line, is that possible?

Here’s another suggestion: you can use rescue to avoid the error you
get if nothing is found:

irb(main):001:0> a=[]
=> []
irb(main):002:0> a << {:name=>“mario”,:value=>“xxx”}
=> [{:name=>“mario”, :value=>“xxx”}]
irb(main):003:0> a << {:name=>“pedro”,:value=>“lsss”}
=> [{:name=>“mario”, :value=>“xxx”}, {:name=>“pedro”, :value=>“lsss”}]
irb(main):004:0> a

irb(main):006:0> a.find {|h| h[:name] == ‘mario’}[:value] rescue nil
=> “xxx”
irb(main):007:0> a.find {|h| h[:name] == ‘missing’}[:value] rescue nil
=> nil

It’s probably cleaner though to do

irb(main):008:0> r = a.find {|h| h[:name] == ‘mario’} and r[:value]
=> “xxx”
irb(main):009:0> r = a.find {|h| h[:name] == ‘missing’} and r[:value]
=> nil

Kind regards

robert