【问题标题】:Rails custom group_byRails 自定义 group_by
【发布时间】:2018-07-11 18:49:03
【问题描述】:

我有一个数组PARTITION 存储天数。

我想group_by 我的posts (ActiveRecord::Relation) 根据他们的年龄和他们所在的分区。

示例:PARTITION = [0, 40, 60, 90]

我想将 0 到 40 天、40 到 60 天、60 到 90 天以及超过 90 天的帖子分组。

请注意,我将从外部源获取数组数据,并且我不想使用where 子句,因为我正在使用includeswhere 触发数据库查询,包括无用。

我该怎么做?

【问题讨论】:

  • 同样可以解决,不过我不认为是重复的。 @Sixty4Bit
  • 您能提供一个您想要的示例输出吗?

标签: ruby-on-rails ruby activerecord group-by


【解决方案1】:

这是一个简单的方法:

posts.each_with_object(Hash.new { |h, k| h[k] = [] }) do |post, hash|
  days_old = (Date.today - post.created_at.to_date).to_i
  case days_old
  when 0..39
    hash[0] << post
  when 40..59
    hash[40] << post
  when 60..89
    hash[60] << post
  when 90..Float::INFINITY # or 90.. in the newest Ruby versions
    hash[90] << post
  end
end

这将遍历帖子,以及具有default value of an empty array 的哈希。

然后,我们只需检查帖子创建的天数,并将其添加到哈希的相关键中。

在处理完所有帖子后返回此哈希。

你可以使用任何你想要的键(例如hash["&lt; 40"]),尽管我使用你的分区来说明目的。

结果将类似于以下内容:

{ 0:  [post_1, post_3, etc],
  40: [etc],
  60: [etc],
  90: [etc] }

希望这会有所帮助 - 如果您有任何问题,请告诉我。


编辑:如果您的 PARTITIONS 来自外部来源,那就有点棘手了,尽管以下方法可行:

# transform the PARTITIONS into an array of ranges
ranges = PARTITIONS.map.with_index do |p, i|
  return 0..(p - 1) if i == 0 # first range is 0..partition minus 1
  return i..Float::INFINITY if i + 1 == PARTITIONS.length # last range is partition to infinity
  p..(PARTITIONS[i + 1] - 1)
end

# loop through the posts with a hash with arrays as the default value
posts.each_with_object(Hash.new { |h, k| h[k] = [] }) do |post, hash|
  # loop through the new ranges
  ranges.each do |range|
    days_old = Date.today - post.created_at.to_date
    hash[range] << post if range.include?(days_old) # add the post to the hash key for the range if it's present within the range
  end
end

最后的编辑:

使用each_with_object 有点傻,group_by 可以完美地处理这个问题。示例如下:

posts.group_by |post|
  days_old = (Date.today - post.created_at.to_date).to_i
  case days_old
  when 0..39
    0
  when 40..59
    40
  when 60..89
    60
  when 90..Float::INFINITY # or 90.. in the newest Ruby versions
    90
  end
end

【讨论】:

  • 这对@UmeshMalhotra 有帮助吗?
【解决方案2】:

假设:

  1. 此分区用于显示目的。
  2. 您要分组的属性是days
  3. 您希望得到一个哈希结果

{ 0 =&gt; [&lt;Post1&gt;], 40 =&gt; [&lt;Post12&gt;], 60 =&gt; [&lt;Post41&gt;], 90 =&gt; [&lt;Post101&gt;] }


将这些方法添加到您的模型中

# post.rb

def self.age_partitioned
  group_by(&:age_partition)
end

def age_partition
  [90, 60, 40, 0].find(days) # replace days by the correct attribute name
end

# Now to use it

Post.where(filters).includes(:all_what_you_want).age_partitioned

【讨论】:

    【解决方案3】:

    根据帖子中的描述,以下操作可以帮助您对数据进行分组:

    result_array_0_40 = [];result_array_40_60 = [];result_array_60_90 = [];result_array_90 = [];
    result_json = {}
    

    现在,我们需要迭代值并手动将它们分组为动态键值对

    PARTITION.each do |x|
        result_array_0_40.push(x) if (0..40).include?(x)
        result_array_40_60.push(x) if (40..60).include?(x)
        result_array_60_90.push(x) if (60..90).include?(x)
        result_array_90.push(x) if x > 90
        result_json["0..40"]  = result_array_0_40
        result_json["40..60"] = result_array_40_60
        result_json["60..90"] = result_array_60_90
        result_json["90+"]    = result_array_90
    end
    

    希望对你有帮助!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多