使用Array.map去除具有相同属性的“重复对象”
问题描述:
正如您在下面的当前代码中所看到的,我发现基于属性recordable_id的重复项。我需要做的是根据四个匹配属性找到重复项:user_id,recordable_type,hero_type,recordable_id。我该如何修改代码?使用Array.map去除具有相同属性的“重复对象”
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
答
使用直红宝石(不是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"
)
答
试试这个:
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日期的副本,留下最初创建的记录。 – keruilin 2010-05-08 01:35:08