Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

find_all elements in an array that match a condition?

I've an array of hash entries, and want to filter based on a paramater passed into the function.

If there are three values in the hash, A, B, and C, I want to do something similar to:

data = [{A:'a1', B:'b1', C:'c1'}, 
    {A:'a1', B:'b2', C:'c1'},
    {A:'a1', B:'b2', C:'c2'}, 
    {A:'a2', B:'b1', C:'c1'},
    {A:'a2', B:'b2', C:'c1'}]

data.find_all{ |d| d[:A].include?params[:A] }
    .find_all{ |d| d[:B].include?params[:B] }
    .find_all{ |d| d[:C].include?params[:C] }

find all where A == 'a1' AND B='b2'

so for above I get: {A:'a1', B:'b2', C:'c1'} and {A:'a1', B:'b2', C:'c2'} * put if / else statements, like params.has_key? 'B' then do something. * modify my code each time a new type of value is added to the Hash map (say now I have 'D').

Note: The key of the hash is a symbol, but the value is a string and I want to do a "contains" not "equals".

I think of it as SQL Select statement with where zero or more '==' clause

like image 478
Raza Avatar asked Feb 05 '14 00:02

Raza


1 Answers

If I understand your question correctly, then I believe that the select method of Array class may be helpful to you.

select takes a block of code which is intended to be a test condition on each element in your array. Any elements within your array which satisfy that test condition will be selected, and the result is an array of those selected elements.

For example:

arr = [ 4, 8, 15, 16, 23, 42 ]
result = arr.select { |element| element > 20 }
puts result   # prints out [23, 42]

In your example, you have an array of hashes, which makes it only slightly more complicated than my example with a simple array of numbers. In your example, we have:

data = [{A:'a1', B:'b1', C:'c1'}, 
        {A:'a1', B:'b2', C:'c1'},
        {A:'a1', B:'b2', C:'c2'}, 
        {A:'a2', B:'b1', C:'c1'},
        {A:'a2', B:'b2', C:'c1'}]

I believe what you want your code to do is something like: Select from my data array all of the hashes where, within the hash, :A equals some value AND :B equals some other value.

Let's say you want to find all of the hashes where :A == 'a1' and :B == 'b2'. You would do that like this:

data.select { |hash_element| hash_element[:A] == 'a1' && hash_element[:B] == 'b2' }

This line returns to you an array with those hashes from your original data array which satisfy the condition we provided in the block - that is, those hashes where :A == 'a1' and :B == 'b2'. Hope that that helps shed some light on your problem!

More information about the select method here:

http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-select

edited - below is an addition to original answer

To follow up on your later question about if/else clauses and the addition of new parameters... the block of code that you pass to select can, of course, be much more complicated than what I've written in the example. You just need to keep this in mind: If the last line of the block of code evaluates to true, then the element will be selected into the result array. Otherwise, it won't be selected.

So, that means you could define a function of your own, and call that function within the condition block passed to select. For example, something like this:

def condition_test(hash_element, key_values)
    result = true
    key_values.each do |pair|
      if hash_element[pair[:key]] != pair[:value]
        result = false
      end
    end
    return result
end

# An example of the key-value pairs you might require to satisfy your select condition.
requirements = [ {:key => :A, :value => 'a1'},
                 {:key => :B, :value => 'b2'} ]

data.select { |hash_element| condition_test(hash_element, requirements) }

This makes your condition block a bit more dynamic, rather than hard-wired for :A == 'a1' and :B == 'b2' like we did in the earlier example. You can tweak requirements on the fly based on the keys and values that you need to look for. You could also modify condition_test to do more than just check to see if the hash value at some key equals some value. You can add in your if/else clauses in condition_test to test for things like the presence of some key, etc.

like image 136
Alvin S. Lee Avatar answered Sep 22 '22 15:09

Alvin S. Lee