2011-09-16 4 views
3

J'ai fait un site pour un jeu PS3 et j'ai beaucoup d'utilisateurs. Je veux faire des tournois basés sur les emplacements des gens et aimerais également cibler les groupes d'âge. Lorsque les utilisateurs inscrivent l'entrée, leur date de naissance est au format AAAA-MM-JJ. Je tire les données et en faire un hachage comme ceci:Ruby on Rails Données démographiques

# 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 

Je ne suis pas un développeur Ruby expert et ne sais pas si l'approche ci-dessus est bon ou il peut être fait une bien meilleure façon, quelqu'un pourrait-il donner moi quelques conseils à ce sujet?

Vive

Répondre

3

Couple de choses à noter dans votre code:

  • vous semblez ignorer le mois et le jour lorsqu'un utilisateur est né
  • vous convertir en chaînes unnecessarilly:

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

    peut s'écrire

    50.years.ago.year 
    
  • valeurs codées en dur dans tout le code

Je commencerais réécriture en trouvant une méthode adéquate pour calculer l'âge exact. This one semble être ok:

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 

alors j'extraire le tableau d'âge à une structure séparée, pour être en mesure de changer facilement, si nécessaire, et ont visuellement ensemble:

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

Ensuite, vous peut prendre comme entrée le tableau des dates de naissance des utilisateurs:

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

Et commencer à trouver une méthode appropriée pour les regrouper en fonction de votre carte, en utilisant inject disent:

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} 

ou, peut-être, en utilisant 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]] 

etc.

+0

Merci pour mettre l'effort dans la réponse, il a contribué à rendre mon code plus élégant! – RailsSon