在红宝石集团用户按年龄范围(Group Users by Age Range in ruby)

2019-06-27 07:41发布

我想列出了年龄范围内的用户数:

Range  : #Users
10-14  : 16
15-21  : 120
22-29  : 312
30-40  : 12131
41-70  : 612
71-120 : 20

我想创建散列的静态数组:

AGE_RANGES = [
  {label:"10 - 14", min:10, max:14},
  {label:"15 - 21", min:15, max:21},
  {label:"22 - 29", min:22, max:29},
  {label:"30 - 40", min:30, max:40},
  {label:"41 - 70", min:41, max:70},
  {label:"71 - 120", min:71, max:120}
]

然后用它为我的搜索过滤器,以及为我的查询。 但是,我想不出获得最大性能的它的方式。

我在我的模型只按年龄分组的方法:

def self.group_by_ageRange(minAge, maxAge)

  query = User.group("users.age")
              .where("users.age BETWEEN minAge and maxAge ")
              .select("users.age,
                        count(*) as number_of_users")

end

有什么建议?

Answer 1:

你想建立一些SQL,看起来像这样:

select count(*),
       case
           when age between 10 and 14 then '10 - 14'
           when age between 15 and 21 then '15 - 21'
           -- ...
       end as age_range
from users
where age between 10 and 120
group by age_range

在ActiveRecord的条款,这将是:

# First build the big ugly CASE, we can also figure out the
# overall max and min ages along the way.
min   = nil
max   = nil
cases = AGE_RANGES.map do |r|
    min = [r[:min], min || r[:min]].min
    max = [r[:max], max || r[:max]].max
    "when age between #{r[:min]} and #{r[:max]} then '#{r[:min]} - #{r[:max]}'"
end

# Then away we go...
age_ranges = Users.select("count(*) as n, case #{cases.join(' ')} end as age_range")
                  .where(:age => min .. max)
                  .group('age_range')
                  .all

这将让你与对象的数组age_ranges和这些对象将有nage_range方法。 如果你想要一个哈希出这一点,那么:

age_ranges = Hash[age_ranges.map { |r| [r.age_range, r.n] }]

这将不包括那些没有任何人在其中,当然范围; 我会离开,作为一个练习留给读者。



Answer 2:

我觉得接受的答案是有点密集。 快,但很难理解和编写。 今天,我想出了一个速度较慢,但​​简单的解决方案。 由于我们年龄分组为范围,我们可以假设,我们不会有超过125个值

这意味着,如果你在一个分组和计数的结果集使用红宝石过滤器,你会不会在超过125项迭代。 这将是比SQL一系列基于组/算慢,但它是我的目的,同时还依赖于数据库的最繁重的速度不够快。 遍历哈希少于125个项目似乎并没有什么大不了的。 特别是当键值对只是INTS这样的:

{
  0 => 0,
  1 => 1,
  3 => 5,
  25 => 3,
  99 => 3
}

这里的psudo代码:

users = User
  .where(age: (min..max))
  .group(:age)
  .count(:age)
group = Hash.new(0)
users.each{|age, count|
      case
      when age <= 10
        group['under 10'] += count
      when age <= 25
        group['11-25'] += count
      when age <= 40
        group['26-40'] += count
      else
        group['41+'] += count
      end
}

注:该解决方案为用户提供的数量在给定的范围内。



文章来源: Group Users by Age Range in ruby