我正在创建一个过滤性别“M”并返回其元素的方法。
考虑到上述要求,您的命名似乎颇具误导性:
def is_male(gender)
# ...
end
上面看起来像一个接受性别并检查是否为男性的方法。我希望是这样的:
is_male('M') #=> true
is_male('F') #=> false
is_male(students) 也不清楚——它会检查给定数组中是否有男学生吗?或者如果所有学生都是男性?不管怎样,这听起来不像是过滤。
让我们首先重命名方法及其参数以更符合您的要求:
def male_students(students)
# ....
end
如果你想使用grep,你必须提供一个pattern,它是一个响应===的对象。正则表达式不起作用,因为它对字符串进行操作,而我们的学生是哈希(更多内容见下文)。您可以改用Proc,它也响应===:
def male_students(students)
is_male = ->(student) { student[:gender] == 'M' }
students.grep(is_male)
end
但是使用select更方便:
def male_students(students)
students.select { |student| student[:gender] == 'M' }
end
另一种选择是为您的学生使用自定义课程,因为现在,您的学生只是散列:
class Student
attr_accessor :name, :grade, :gender
def initialize(name:, grade:, gender:)
@name = name
@grade = grade
@gender = gender
end
def male?
gender == 'M'
end
def female?
gender == 'F'
end
end
现在,相应地更改您的数组:
students = [
Student.new(name: 'John', grade: 8, gender: 'M'),
Student.new(name: 'Sarah', grade: 12, gender: 'F'),
Student.new(name: 'Bob', grade: 16, gender: 'M'),
Student.new(name: 'Johnny', grade: 2, gender: 'M'),
Student.new(name: 'Ethan', grade: 4, gender: 'M'),
Student.new(name: 'Paula', grade: 8, gender: 'F'),
Student.new(name: 'Donald', grade: 5, gender: 'M'),
Student.new(name: 'Jennifer', grade: 13, gender: 'F'),
Student.new(name: 'Courtney', grade: 15, gender: 'F'),
Student.new(name: 'Jane', grade: 9, gender: 'F'),
]
你可以使用这个非常简单的语法:
students.select(&:male?)
#=>
# [
# #<Student:0x00007fb18d826ce8 @name="John", @grade=8, @gender="M">,
# #<Student:0x00007fb18d826b58 @name="Bob", @grade=16, @gender="M">,
# #<Student:0x00007fb18d826a90 @name="Johnny", @grade=2, @gender="M">,
# #<Student:0x00007fb18d8269c8 @name="Ethan", @grade=4, @gender="M">,
# #<Student:0x00007fb18d826838 @name="Donald", @grade=5, @gender="M">
# ]
或Array/Enumerable中的任何其他有用方法:
students.any?(&:male?) #=> true
students.all?(&:male?) #=> false
students.count(&:male?) #=> 5