Ruby on Rails Демографические данные - PullRequest
3 голосов
/ 16 сентября 2011

Я сделал сайт для игры для PS3, и у меня довольно много пользователей.Я хочу проводить турниры по местам проживания людей, а также хочу ориентироваться на возрастные группы.Когда пользователи регистрируются на входе, там указывается дата рождения в формате ГГГГ-ММ-ДД.Я извлекаю данные и превращаю их в хеш-код, например:

# Site.rb

has_many :members

def ages
  ages = {"Under 18" => 0, "19-24" => 0, "25-35" => 0, "36-50" => 0, "51-69" => 0,"70+" => 0}
  ages_results = self.members.count("DATE_FORMAT(dob, '%Y')", :group =>"DATE_FORMAT(dob, '%Y')")
  ages_results.each do |k,v|
    k = k.to_i
    if k.between?(18.years.ago.strftime("%Y").to_i, 0.years.ago.strftime("%Y").to_i)
      ages["Under 18"] += v
    elsif k.between?(24.years.ago.strftime("%Y").to_i, 19.years.ago.strftime("%Y").to_i)
      ages["19-24"] += v
    elsif k.between?(35.years.ago.strftime("%Y").to_i, 25.years.ago.strftime("%Y").to_i)
      ages["25-35"] += v
    elsif k.between?(50.years.ago.strftime("%Y").to_i, 36.years.ago.strftime("%Y").to_i)
      ages["36-50"] += v
    elsif k.between?(69.years.ago.strftime("%Y").to_i, 51.years.ago.strftime("%Y").to_i)
      ages["51-69"] += v 
    elsif k > 70.years.ago.strftime("%Y").to_i
      ages["70+"] += v
    end
  end
  ages
end

Я не являюсь опытным разработчиком ruby ​​и не уверен, что вышеприведенный подход хорош или его можно сделать гораздо лучше,Кто-нибудь дать мне совет по этому поводу?

Приветствия

1 Ответ

3 голосов
/ 16 сентября 2011

Пара вещей, которые нужно отметить в вашем коде:

  • вы, кажется, игнорируете месяц и день рождения пользователя
  • Вы конвертируете в и из строк без необходимости:

    50.years.ago.strftime("%Y").to_i
    

    можно записать как

    50.years.ago.year
    
  • жестко закодированные значения по всему коду

Я бы начал переписывать с поиска подходящего метода для расчета точного возраста. Этот вроде бы в порядке:

require 'date'

def age(dob)
  now = Time.now.utc.to_date
  now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end

Затем я бы извлек таблицу возраста в отдельную структуру, чтобы можно было легко изменить ее при необходимости и визуально собрать вместе:

INF = 1/0.0 # convenient infinity
age_groups = {
  (0..18) => 'Under 18',
  (19..24) => '19-24',
  (25..35) => '25-35',
  (36..50) => '36-50',
  (51..69) => '51-69',
  (70..INF) => '70+'
}

Далее вы можете взять в качестве входных данных массив дат рождения пользователей:

users_dobs = [Date.new(1978,4,16), Date.new(2001,6,13), Date.new(1980,10,22)]

И начинаем искать подходящий метод для группировки их на основе вашей карты, скажем, используя inject:

p users_dobs.each_with_object({}) {|dob, result|
  age_group = age_groups.keys.find{|ag| ag === age(dob)}
  result[age_group] ||= 0
  result[age_group] += 1
}
#=>{25..35=>2, 0..18=>1}

или, возможно, используя group_by

p users_dobs.group_by{|dob|
  age_groups.keys.find{|ag| ag === age(dob)}
}.map{|k,v| [age_groups[k], v.count]}
#=>[["25-35", 2], ["Under 18", 1]]

и т.д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...