How do I search within an array of hashes by hash values in ruby?

207,139

Solution 1

You're looking for Enumerable#select (also called find_all):

@fathers.select {|father| father["age"] > 35 }
# => [ { "age" => 40, "father" => "Bob" },
#      { "age" => 50, "father" => "Batman" } ]

Per the documentation, it "returns an array containing all elements of [the enumerable, in this case @fathers] for which block is not false."

Solution 2

this will return first match

@fathers.detect {|f| f["age"] > 35 }

Solution 3

if your array looks like

array = [
 {:name => "Hitesh" , :age => 27 , :place => "xyz"} ,
 {:name => "John" , :age => 26 , :place => "xtz"} ,
 {:name => "Anil" , :age => 26 , :place => "xsz"} 
]

And you Want To know if some value is already present in your array. Use Find Method

array.find {|x| x[:name] == "Hitesh"}

This will return object if Hitesh is present in name otherwise return nil

Solution 4

(Adding to previous answers (hope that helps someone):)

Age is simpler but in case of string and with ignoring case:

  • Just to verify the presence:

@fathers.any? { |father| father[:name].casecmp("john") == 0 } should work for any case in start or anywhere in the string i.e. for "John", "john" or "JoHn" and so on.

  • To find first instance/index:

@fathers.find { |father| father[:name].casecmp("john") == 0 }

  • To select all such indices:

@fathers.select { |father| father[:name].casecmp("john") == 0 }

Share:
207,139

Related videos on Youtube

doctororange
Author by

doctororange

Updated on August 13, 2020

Comments

  • doctororange
    doctororange almost 4 years

    I have an array of hashes, @fathers.

    a_father = { "father" => "Bob", "age" =>  40 }
    @fathers << a_father
    a_father = { "father" => "David", "age" =>  32 }
    @fathers << a_father
    a_father = { "father" => "Batman", "age" =>  50 }
    @fathers << a_father 
    

    How can I search this array and return an array of hashes for which a block returns true?

    For example:

    @fathers.some_method("age" > 35) #=> array containing the hashes of bob and batman
    

    Thanks.

    • ARK
      ARK almost 4 years
      This question is quite helpful but I couldn't stop wondering why would one need an array of @fathers :P
  • Milan Novota
    Milan Novota over 14 years
    Oh! You were the first one! Deleting my answer and +1.
  • TJ Biddle
    TJ Biddle almost 11 years
    I prefer this over #select - But all goes for your use case. #detect will return nil if no match is found, while #select, in @Jordan's answer, will return [].
  • Alter Lagos
    Alter Lagos over 10 years
    You could also use find instead of detect for a more readable code
  • Leigh  McCulloch
    Leigh McCulloch about 10 years
    As a note, if you wanted only to find a single one (the first one) you can use @fathers.find {|father| father["age"] > 35 } instead.
  • user12341234
    user12341234 about 9 years
    find can get confusing in rails, however.
  • Ian Warner
    Ian Warner over 7 years
    Is it possible to return the index of where this was found in the original array of hashes?
  • Jordan Running
    Jordan Running over 7 years
    @IanWarner Yes. I suggest looking at the docs for the Enumerable module. If you still can't figure it out, post a new question.
  • Ian Warner
    Ian Warner over 7 years
    I just did this index = ARRAY.index { | h | h[ :code ] == ARRAY[ "code" ] }
  • user1735921
    user1735921 over 7 years
    what is the fastest way to find it using the unique hash value, with no condition, the condition is father["unique_id"] == 35 and not > and we use a unique id instead of age ? Any suggestions ? I wan to find out the the father with that id.
  • Naveed
    Naveed almost 7 years
    select and detect aren't same, select will transverse the whole array, while detect will stop as soon as the first match is found. IF you're looking for ONE match @fathers.select {|f| f["age"] > 35 }.first vs @fathers.detect {|f| f["age"] > 35 } for performance and readability, my vote goes for detect
  • arjun
    arjun about 6 years
    If the name was lowercase like "hitesh", it wont return the hash. How can we account for word casing as well in such cases?
  • Hitesh Ranaut
    Hitesh Ranaut about 6 years
    you can use something like. array.find {|x| x[:name].downcase == "Hitesh".downcase }
  • ARK
    ARK almost 4 years
    @arjun array.any?{ |element| element[:name].casecmp("hitesh")==0 } should work for any case in start or anywhere in the string i.e. for "Hitesh", "hitesh" or "hiTeSh"
  • ARK
    ARK almost 4 years
    actually check my answer: stackoverflow.com/a/63375479/10313894
  • netwire
    netwire almost 3 years
    find is an alias for detect method