Search code examples
ruby-on-railsrubyenumerable

Understanding grep within Enumerable module


I greatly appreciate any assistance on my first stack-overflow post!

I was generally confused why I am receiving and empty array every time I try to run my code. I am creating a method that will filter for a gender of "M" and return its elements.

I am sure there are a multitude of ways to successfully run this code but I was interested in using grep and its functionality. It being a shortcut and all I thought it would be good to learn. Thank you once again.

students = [
    {name: 'John', grade: 8, gender: 'M'},
    {name: 'Sarah', grade: 12, gender: 'F'},
    {name: 'Bob', grade: 16, gender: 'M'},
    {name: 'Johnny', grade: 2, gender: 'M'},
    {name: 'Ethan', grade: 4, gender: 'M'},
    {name: 'Paula', grade: 8, gender: 'F'},
    {name: 'Donald', grade: 5, gender: 'M'},
    {name: 'Jennifer', grade: 13, gender: 'F'},
    {name: 'Courtney', grade: 15, gender: 'F'},
    {name: 'Jane', grade: 9, gender: 'F'}
]
def is_male(gender)
  gender.grep(/M/) { |gend| gend[:gender] }
end
p is_male(students)

Solution

  • From the docs of Enumerable#grep:

    grep(pattern) → array
    grep(pattern) { |obj| block } → array
    

    Returns an array of every element in enum for which Pattern === element. If the optional block is supplied, each matching element is passed to it, and the block’s result is stored in the output array.

    The important part is this method returns elements that evaluate Pattern === element to true. But /M/ === {name: 'John', grade: 8, gender: 'M'} does not return true, same for all other elements in your array.

    Therefore your result set is empty in the first place.

    The block – { |gend| gend[:gender] } in your example – is only evaluated when and after there was a pattern match. The block changes the return value of the whole call but not how the pattern matching is done.

    Please note the docs for Rexgxp#=== in this context too.