Объедините два итератора each_with_object - PullRequest
0 голосов
/ 12 июня 2018

У меня есть два метода, которые делают почти одно и то же.Я хотел бы объединить их в один метод, чтобы сделать их сухими.

  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> }

Ответы [ 3 ]

0 голосов
/ 12 июня 2018

Общая часть выглядит следующим образом:

@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
0 голосов
/ 12 июня 2018

Хотя для этого не используется each_with_object, кажется, что это еще один жизнеспособный вариант, если вы используете ruby> = 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 (в основном потому, что подпись и сокращение также были украдены).

0 голосов
/ 12 июня 2018
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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...