我有两种方法几乎完全相同。我想将它们组合成一种方法,使它们变干。
def build_training_organization_filters
@dive_centers.each_with_object(Hash.new(0)) { |obj, counts| counts[obj.training_organizations.first.short_name] += 1 }
end
def build_dive_center_type_filters
@dive_centers.each_with_object(Hash.new(0)) { |obj, counts| counts[obj.dive_center_type] += 1 }
end
输出最终将是JSON输出,如下所示:
{ training_org_filter: <data>, dive_center_filter: <data> }
答案 0 :(得分:6)
共同部分似乎是:
@dive_centers.each_with_object(Hash.new(0)) { |obj, counts| counts[...] += 1 }
...
obj.training_organizations.first.short_name
和
obj.dive_center_type
以上两者都取决于obj
,因此我们可以将公共部分提取到单独的方法中,并使用yield
从调用者处获取密钥:
def count_by
@dive_centers.each_with_object(Hash.new(0)) { |o, h| h[yield(o)] += 1 }
end
即。我们通过传递一个块来提供具体部分:
def build_training_organization_filters
count_by { |center| center.training_organizations.first.short_name }
end
def build_dive_center_type_filters
count_by { |center| center.dive_center_type }
end
答案 1 :(得分:4)
def build(*properties)
@dive_centers.each_with_object(Hash.new(0)) do |obj, counts|
index = properties.reduce(obj) { |o, m| o.public_send(m) }
counts[index] += 1
end
end
并称之为:
build(:dive_center_type)
build(:training_organizations, :first, :short_name)
答案 2 :(得分:0)
虽然这不使用each_with_object
,但如果您使用ruby&gt; = 2.4,它似乎是另一个可行的选项。这使用Enumberable#group_by
和Hash#transform_values
,但它确实需要多个循环,这是不太理想的。
def count_by(*chain)
@dive_centers.group_by do |obj|
chain.reduce(obj) {|o,m| o.public_send(m)}
end.transform_values(&:count)
end
用法
count_by(:dive_center_type)
count_by(:training_organizations, :first, :short_name)
用法与@ mudasobwa的回答相同(主要是因为签名和减少也被盗了。)