Рефакторинг Ruby If / Else с итерацией и вставкой в ​​массив - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь очистить метод, который перебирает данные, помещаемые в массивы.Это что-то вроде:

def sort_by_title(authors)
 general = []
 fiction = []
 factual = []
 food = []
 other = []

 authors.each do |a|
  if a.tag.include?('General')
   general << a
  elsif a.tag.include?('Historical')
    fiction << a if a.tag.include?('iction')
    factual <<a if a.tag.include?('actual')
  elseif a.tag.include?('Food')
    food << a
  else
    other << a
  end
 end
 (general + fiction + factual + food + other).flatten
end
end

Рубокоп ударил меня: Metrics/AbcSize and Metrix/Perceived Complexity.Есть ли более чистый способ сделать это?

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Я бы выбрал case:

authors.each_with_object(Hash.new { |h, k| h[k] = [] }) do |a, hash|
  case a.tag
  when /General/ then h[:general] << a
  when /Historical.*iction/ then h[:fiction] << a
  when /Historical.*actual/ then h[:factual] << a
  when /Food/ then h[:food] << a
  else h[:other] << a
end.values.flatten

Или более захватывающий и семантически правильный подход с Enumerable#sort_by:

authors.sort_by do |a|
  [
    10 if a.tag.include?('General'),
    if a.tag.include?('iction')
      8
    elsif if a.tag.include?('actual')
      6
    end if a.tag.include?('Historical'),
    4 if a.tag.include?('Food'),
    2
  ].compact.sum
end
0 голосов
/ 15 декабря 2018

Вам нужны они сгруппированы или отсортированы?Если это просто отсортировано, можете ли вы использовать sort_by с полем поиска?

TAGS = {
  'General' => 1,
  'Fiction' => 2,
  'Factual' => 3,
  'Food' => 4,
  'Other' => 5
}

authors = [
  { name: 'Joe', tag: 'General' },
  { name: 'Sue', tag: 'Fiction' },
  { name: 'Sally', tag: 'Food' },
  { name: 'Oliver', tag: 'Factual' },
  { name: 'Bob', tag: 'Other' },
  { name: 'Billy', tag: 'General' }
]

sorted_authors =
  authors.sort_by do |author|
    TAGS[author[:tag]] # This would be author.tag in your example
  end

puts sorted_authors

Выход

{:name=>"Joe", :tag=>"General"}
{:name=>"Billy", :tag=>"General"}
{:name=>"Sue", :tag=>"Fiction"}
{:name=>"Oliver", :tag=>"Factual"}
{:name=>"Sally", :tag=>"Food"}
{:name=>"Bob", :tag=>"Other"}
0 голосов
/ 14 декабря 2018

Вы можете использовать #group_by:

def sort_by_title(authors)
  grouped = authors.group_by do |a| 
    if a.tag.include?('General')
      :general
    elsif a.tag.include?('Historical')
      :fiction if a.tag.include?('iction')
      :factual if a.tag.include?('actual')
    elsif a.tag.include?('Food')
      :food
    else
      :other
    end
  end
  grouped.values.flatten
end

РЕДАКТИРОВАТЬ:

Чтобы сделать его чище, вы можете извлечь метод, определяющий жанр:

class Author
  def genre
    if tag.include?('General')
      :general
    elsif tag.include?('Historical')
      :fiction if tag.include?('iction')
      :factual if tag.include?('actual')
    elsif tag.include?('Food')
      :food
    else
      :other
    end
  end
end

def sort_by_title(authors)
  authors.group_by(&:genre).values.flatten
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...