2011-12-16 3 views
1

Так у меня есть этот код:Ruby, значение bucketing, украсьте код

def self.age_to_bucket(age) 
    age = age.to_i 

    if age >= 0 && age <= 12 
    1 
    elsif age >= 13 && age <= 17 
    2 
    elsif age >= 18 && age <= 24 
    3 
    elsif age >= 25 && age <= 29 
    4 
    elsif age >= 30 && age <= 34 
    5 
    elsif age >= 35 && age <= 39 
    6 
    elsif age >= 40 && age <= 49 
    7 
    elsif age >= 50 && age <= 64 
    8 
    elsif age >= 65 
    9 
    else 
    0 
    end 
end 

Как я могу улучшить этот код без потери его читаемости?

Я знаю, что могу использовать #in? с диапазонами, например:

if age.in? (0..12) 

но #in? в ActiveSupport, и я предпочел бы использовать более самостоятельный путь.

+0

Вам это нравится или это слишком абстракция? '[0, 12, 13, 17, ...]. Find_interval (15) # => 2'. Его довольно легко реализовать (немного сложнее сделать это эффективно). – tokland

+0

Я имею в виду: '[0, 13, 18, ...]. Find_interval (15)' – tokland

+0

Я бы ничего не реализовал сам, потому что мне нужен этот код только в одном месте. –

ответ

6

Один из способов заключается в использовании случай

result = case age 
when 0..12 then 1 
when 13..17 then 2 
when 18..24 then 3 
when 25..29 then 4 
-------- so on 
else 0 
end 

Другой способ будет устранить в состоянии избыточной & &.

if age < 0 
    0 
elsif age < 13 
    1 
elsif age < 18 
    2 
elsif age < 25 
    3 
elsif age < 30 
    4 
elsif age < 35 
    5 
elsif age < 40 
    6 
elsif age < 50 
    7 
elsif age < 65 
    8 
else 
    9 

UPD: окончательный вариант кода в результате всех советов в этой теме: https://gist.github.com/1485288

+0

как бы вы выразили «возраст» 65' в «случае»? –

+1

'(65..Float :: INFINITY)'. Создайте свою собственную бесконечность для версии 1.8: 'infinity = 1.0/0' – tokland

+0

Текущая версия выглядит так: https://gist.github.com/1485288 Гораздо лучше, имхо. Спасибо, парни. –

1

Вы можете переписать if age.in? (0..12) в (0..12).include? age, который vanilla Ruby.

+0

Да, но это выглядит хуже :-) –

0
irb(main):010:0> a = {1 => 0..12, 2 => 13..17} # insert other values here 
=> {1=>0..12, 2=>13..17} 
irb(main):011:0> age = 16 
=> 16 
irb(main):012:0> a.keys.find {|k| a[k].include?(age) } 
=> 2 
+0

Что относительно 'elsif age> = 65' case, как вы сделаете этот диапазон? – megas

+0

Проверьте значение nil и добавьте тест if. – Geo

2
def self.age_to_bucket age 
    case age=age.to_i 
    when 0..12 then 1 
    when 13..17 then 2 
    when 18..24 then 3 
    when 25..29 then 4 
    when 30..34 then 5 
    when 35..39 then 6 
    when 40..49 then 7 
    when 50..64 then 8 
    else age >= 65 ? 9 : 0 
    end 
end 
1

Просто для удовольствия (это не эффективный способ, но для небольших массивов просто отлично):

ranges = [0, 13, 18, 25, 30, 35, 40, 50, 65, Float::INFINITY].each_cons(2).map { |a, b| (a..b) } 
n = ranges.map.with_index { |range, idx| idx if range.include?(15) }.compact.first + 1 
#=> 2 

Обратите внимание, что если интервалы были динамическими вы бы реализовать он аналогичным образом.

+0

Теперь это «умный» и скрывающий код :-) –

+1

@Sergei: «сокрытие» в том смысле, что это не так «ясно» статический случай, хорошо, но программно вам нужно будет что-то подобное. Программирование касается написания абстракций, не бойтесь их. 'map.with_index' действителен Ruby 1.9. – tokland

+0

Да, я имею в виду, для моего случая статических интервалов это слишком сложное решение. Динамические интервалы - еще одна история. –

Смежные вопросы