【问题标题】:Removing “duplicate objects” with same attributes using Array.map使用 Array.map 删除具有相同属性的“重复对象”
【发布时间】:2010-05-08 00:03:24
【问题描述】:

正如您在下面的当前代码中看到的,我正在根据属性 recordable_id 找到重复项。我需要做的是根据四个匹配属性找到重复项:user_id、recordable_type、hero_type、recordable_id。如何修改代码?

heroes = User.heroes

for hero in heroes
  hero_statuses = hero.hero_statuses

  seen = []

  hero_statuses.sort! {|a,b| a.created_at <=> b.created_at } # sort by created_at
  hero_statuses.each do |hero_status|
    if seen.map(&:recordable_id).include? hero_status.recordable_id # check if the id has been seen already
      hero_status.revoke
    else
      seen << hero_status # if not, add it to the seen array
    end
  end
end

【问题讨论】:

  • 我想去掉 created_at 日期最近的重复项,留下最初创建的记录。

标签: ruby-on-rails ruby arrays duplicate-removal


【解决方案1】:

试试这个:

HeroStatus.all(:group =>  "user_id, recordable_type, hero_type, recordable_id",
               :having => "count(*) > 1").each do |status|
  status.revoke 
end

编辑 2 要撤消所有最新的重复条目,请执行以下操作:

HeroStatus.all(:joins => "(
     SELECT   user_id, recordable_type, hero_type, 
              recordable_id, MIN(created_at) AS created_at
     FROM     hero_statuses
     GROUP BY user_id, recordable_type, hero_type, recordable_id
     HAVING   COUNT(*) > 1
   ) AS A ON A.user_id         = hero_statuses.user_id         AND 
             A.recordable_type = hero_statuses.recordable_type AND
             A.hero_type       = hero_statuses.hero_type       AND
             A.recordable_id   = hero_statuses.recordable_id   AND
             A.created_at      < hero_statuses.created_
").each do |status|
  status.revoke 
end

【讨论】:

  • 不错。这让我更接近了。这是我忘记提及的另一个皱纹。我想删除最近 created_at 日期的重复项,留下最初创建的记录。
  • 更新了答案,看看吧。
  • 谢谢坎!这很好用。我正在寻找基于红宝石的答案,所以要检查马克的。但感谢您的帮助!
  • 我没有给你一个基于 Ruby 的解决方案,因为它对你的用例来说效率很低。这是 DB 最擅长的事情。您可以将 Ruby 方法用于小数据集(
【解决方案2】:

直接使用 Ruby(不是 SQL 服务器):

heroes = User.heroes

for hero in heroes
  hero_statuses = hero.hero_statuses

  seen = {}

  hero_statuses.sort_by!(&:created_at)
  hero_statuses.each do |status|
    key = [status.user_id, status.recordable_type, status.hero_type, status.recordable_id]
    if seen.has_key?(key)
      status.revoke
    else
      seen[key] = status # if not, add it to the seen array
    end
  end

  remaining = seen.values
end

对于查找,请始终使用Hash(或Set,但在这里我认为保留已保留的状态会很好)

注意:我使用了sort_by!,但这是 1.9.2 的新功能,所以使用sort_by(或require "backports"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 2015-12-14
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多