按 rails 中的年龄范围对用户进行分组
Group users by age range in rails
根据“PESEL”数字,我必须按年龄对用户进行分组。我创建了类似这样的东西并且它正在运行,但是......老实说,它对我来说看起来很糟糕。
帮助者:
def years(pesel)
years = (0..99).to_a
birth_year = []
case pesel[2..3].to_i
when 0..19
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'1900').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'1900').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
when 20..39
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'2000').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'2000').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
when 40..59
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'2100').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'2100').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
end
end
控制器:
def grouped_by_age
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(study_participation.user.profile.pesel)
end
end
一个小的解释和例子。我对顺序对应的前 6 个数字感兴趣:出生年份、月份、日期
所以如果我的 PESEL == '980129(...)',那么我出生于 1998 年 1 月 29 日
如果某人出生于 2000 年,那么我们将 20 添加到 pesel-month(例如 '002129(...)' 它是 2000 年 1 月 29 日。如果某人出生于 2100 年,那么我们将 40 添加到 pesel-月号。
我已经解释了 pesel 数是什么,现在我想用它做什么。
我需要按年龄范围对用户进行分组。上面的函数 returns 是这样的:
{0=>"118-122",
1=>"118-122",
2=>"118-122",
3=>"118-122",
4=>"118-122",
5=>"113-117",
6=>"113-117",
7=>"113-117",
8=>"113-117",
9=>"113-117",
10=>"108-112",
11=>"108-112",
12=>"108-112",
13=>"108-112",
14=>"108-112",
15=>"103-107",
16=>"103-107",
17=>"103-107",
18=>"103-107",
19=>"103-107",(...)}
不幸的是,这不是很有效,因为对于每个用户(最多 4000 个)我必须从头开始执行这些功能。有什么办法可以提高效率吗?我考虑过将此哈希存储为 const 并每年更改一次,但我真的不知道该怎么做或是否可行。
编辑:
忘了说:我需要比较用户年龄和hash,所以我可以提取年龄范围
编辑2:
基于@yoones 的回答,我创建了这样的东西:
帮助者:
def years_cache
years = []
201.times do |index|
years += [Date.today.year - (1900 + index)]
end
birth_year = []
60.times do |index|
year = if index < 20
'1900'
elsif index < 40
'2000'
else
'2100'
end
first_number = 5 * (index % 20)
second_number = (5 * (index % 20)) + 4
first_year = Date.today.year - second_number.to_s.rjust(4, year).to_i
second_year = Date.today.year - first_number.to_s.rjust(4, year).to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
@hash = (years.zip multiplied_birth_years).to_h
end
def years(cache, pesel)
day = pesel[4..5]
case pesel[2..3].to_i
when 0..19
month = pesel[2..3]
year = pesel[0..1].prepend('19')
when 20..39
month = (pesel[2..3].to_i - 20).to_s
year = pesel[0..1].prepend('20')
when 40..59
month = (pesel[2..3].to_i - 40).to_s
year = pesel[0..1].prepend('21')
end
birth_date = Time.strptime("#{day}/#{month}/#{year}", '%d/%m/%Y')
age = ((Time.zone.now - birth_date) / 1.year.seconds).floor
cache.fetch(age)
end
控制器:
def grouped_by_age
cache = years_cache()
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(cache, study_participation.user.profile.pesel)
end
end
与其每次要查看页面时都从 PESEL 进行复杂的出生日期计算,不如执行一次并将其存储在数据库中。在用户上设置出生日期列很有意义。
然后当你想对它们进行分组时,你甚至可以通过数据库来完成。如果你还需要在ruby中完成,那么获取出生年份就像user.birth_date.year
一样简单
为了根据年龄将用户分组到 5 岁的范围内,向模型添加一个 age_range
方法并按该方法分组。
@study_participations.includes(user: :profile).group_by do |study_participation|
study_participation.user.age_range
end
其中age_range
可以是例如
def age_range
(Date.today.year - birth_date.year) / 5) * 5
end
随心所欲地格式化
我想您至少可以构建一次缓存,然后在循环中使用它。下面的代码并不漂亮,只是为了说明我的意思:
def build_year_cache(index, rjust_str)
first_number = 5 * index
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4, rjust_str).to_i
second_year = Date.today.year - first_number.to_s.rjust(4, rjust_str).to_i
"#{first_year}-#{second_year}"
end
def build_years_cache
cache = {}
years = (0..99).to_a
[
[0..19, '1900'],
[20..39, '2000'],
[40..59, '2100']
].each do |range, rjust_str|
birth_year = []
20.times do |index|
birth_year.append(build_year_cache(index, rjust_str))
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
cache[range] = Hash[years.zip multiplied_birth_years]
end
cache
end
def years(pesel, cache)
year = pesel[0..1].to_i
month = pesel[2..3].to_i
range = cache.keys.find { |k, v| k.include?(month) }
cache[range].fetch(year)
end
def grouped_by_age
cache = build_years_cache
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(study_participation.user.profile.pesel, cache)
end
end
根据“PESEL”数字,我必须按年龄对用户进行分组。我创建了类似这样的东西并且它正在运行,但是......老实说,它对我来说看起来很糟糕。
帮助者:
def years(pesel)
years = (0..99).to_a
birth_year = []
case pesel[2..3].to_i
when 0..19
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'1900').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'1900').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
when 20..39
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'2000').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'2000').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
when 40..59
20.times do |index|
first_number = index % 2 == 0 ? (5 * index) : ((5 * index))
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4,'2100').to_i
second_year = Date.today.year - first_number.to_s.rjust(4,'2100').to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
hash = Hash[years.zip multiplied_birth_years]
hash.fetch(pesel[0..1].to_i)
end
end
控制器:
def grouped_by_age
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(study_participation.user.profile.pesel)
end
end
一个小的解释和例子。我对顺序对应的前 6 个数字感兴趣:出生年份、月份、日期 所以如果我的 PESEL == '980129(...)',那么我出生于 1998 年 1 月 29 日 如果某人出生于 2000 年,那么我们将 20 添加到 pesel-month(例如 '002129(...)' 它是 2000 年 1 月 29 日。如果某人出生于 2100 年,那么我们将 40 添加到 pesel-月号。 我已经解释了 pesel 数是什么,现在我想用它做什么。 我需要按年龄范围对用户进行分组。上面的函数 returns 是这样的:
{0=>"118-122",
1=>"118-122",
2=>"118-122",
3=>"118-122",
4=>"118-122",
5=>"113-117",
6=>"113-117",
7=>"113-117",
8=>"113-117",
9=>"113-117",
10=>"108-112",
11=>"108-112",
12=>"108-112",
13=>"108-112",
14=>"108-112",
15=>"103-107",
16=>"103-107",
17=>"103-107",
18=>"103-107",
19=>"103-107",(...)}
不幸的是,这不是很有效,因为对于每个用户(最多 4000 个)我必须从头开始执行这些功能。有什么办法可以提高效率吗?我考虑过将此哈希存储为 const 并每年更改一次,但我真的不知道该怎么做或是否可行。
编辑: 忘了说:我需要比较用户年龄和hash,所以我可以提取年龄范围
编辑2: 基于@yoones 的回答,我创建了这样的东西:
帮助者:
def years_cache
years = []
201.times do |index|
years += [Date.today.year - (1900 + index)]
end
birth_year = []
60.times do |index|
year = if index < 20
'1900'
elsif index < 40
'2000'
else
'2100'
end
first_number = 5 * (index % 20)
second_number = (5 * (index % 20)) + 4
first_year = Date.today.year - second_number.to_s.rjust(4, year).to_i
second_year = Date.today.year - first_number.to_s.rjust(4, year).to_i
birth_year += ["#{first_year}-#{second_year}"]
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
@hash = (years.zip multiplied_birth_years).to_h
end
def years(cache, pesel)
day = pesel[4..5]
case pesel[2..3].to_i
when 0..19
month = pesel[2..3]
year = pesel[0..1].prepend('19')
when 20..39
month = (pesel[2..3].to_i - 20).to_s
year = pesel[0..1].prepend('20')
when 40..59
month = (pesel[2..3].to_i - 40).to_s
year = pesel[0..1].prepend('21')
end
birth_date = Time.strptime("#{day}/#{month}/#{year}", '%d/%m/%Y')
age = ((Time.zone.now - birth_date) / 1.year.seconds).floor
cache.fetch(age)
end
控制器:
def grouped_by_age
cache = years_cache()
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(cache, study_participation.user.profile.pesel)
end
end
与其每次要查看页面时都从 PESEL 进行复杂的出生日期计算,不如执行一次并将其存储在数据库中。在用户上设置出生日期列很有意义。
然后当你想对它们进行分组时,你甚至可以通过数据库来完成。如果你还需要在ruby中完成,那么获取出生年份就像user.birth_date.year
为了根据年龄将用户分组到 5 岁的范围内,向模型添加一个 age_range
方法并按该方法分组。
@study_participations.includes(user: :profile).group_by do |study_participation|
study_participation.user.age_range
end
其中age_range
可以是例如
def age_range
(Date.today.year - birth_date.year) / 5) * 5
end
随心所欲地格式化
我想您至少可以构建一次缓存,然后在循环中使用它。下面的代码并不漂亮,只是为了说明我的意思:
def build_year_cache(index, rjust_str)
first_number = 5 * index
second_number = index % 2 == 0 ? (5 * index + 4) : ((5 * index) + 4)
first_year = Date.today.year - second_number.to_s.rjust(4, rjust_str).to_i
second_year = Date.today.year - first_number.to_s.rjust(4, rjust_str).to_i
"#{first_year}-#{second_year}"
end
def build_years_cache
cache = {}
years = (0..99).to_a
[
[0..19, '1900'],
[20..39, '2000'],
[40..59, '2100']
].each do |range, rjust_str|
birth_year = []
20.times do |index|
birth_year.append(build_year_cache(index, rjust_str))
end
multiplied_birth_years = ([birth_year] * 5).inject(&:zip).flatten
cache[range] = Hash[years.zip multiplied_birth_years]
end
cache
end
def years(pesel, cache)
year = pesel[0..1].to_i
month = pesel[2..3].to_i
range = cache.keys.find { |k, v| k.include?(month) }
cache[range].fetch(year)
end
def grouped_by_age
cache = build_years_cache
@yearsbook = @study_participations.includes(user: :profile).group_by do |study_participation|
years(study_participation.user.profile.pesel, cache)
end
end