Il y a un an I monkey patched une sorte de instance_variables_compare
cryptique sur Object
. Je suppose que tu pourrais utiliser ça.
class Object
def instance_variables_compare(o)
Hash[*self.instance_variables.map {|v|
self.instance_variable_get(v)!=o.instance_variable_get(v) ?
[v,o.instance_variable_get(v)] : []}.flatten]
end
end
Un exemple ringard
require 'Date'
class Cheese
attr_accessor :name, :weight, :expire_date
def initialize(name, weight, expire_date)
@name, @weight, @expire_date = name, weight, expire_date
end
end
stilton=Cheese.new('Stilton', 250, Date.parse("2010-12-02"))
gorgonzola=Cheese.new('Gorgonzola', 250, Date.parse("2010-12-17"))
RIR est mon arme de choix
>> stilton.instance_variables_compare(gorgonzola)
=> {"@name"=>"Gorgonzola", "@expire_date"=>#<Date: 4910305/2,0,2299161>}
>> gorgonzola.instance_variables_compare(stilton)
=> {"@name"=>"Stilton", "@expire_date"=>#<Date: 4910275/2,0,2299161>}
>> stilton.expire_date=gorgonzola.expire_date
=> #<Date: 4910305/2,0,2299161>
>> stilton.instance_variables_compare(gorgonzola)
=> {"@name"=>"Gorgonzola"}
>> stilton.instance_variables_compare(stilton)
=> {}
Comme vous pouvez le voir les instance_variables_compare
renvoie un Hash vide si les deux objets a la même contenu.
Un tableau de fromage
stilton2=Cheese.new('Stilton', 210, Date.parse("2010-12-02"))
gorgonzola2=Cheese.new('Gorgonzola', 250, Date.parse("2010-12-17"))
arr=[]<<stilton<<stilton2<<gorgonzola<<gorgonzola2
Un hachage sans problème et une avec
h={}
problems=Hash.new([])
arr.each {|c|
if h.has_key?(c.name)
if problems.has_key?(c.name)
problems[c.name]=problems[c.name]<<c
elsif h[c.name].instance_variables_compare(c) != {}
problems[c.name]=problems[c.name]<<c<<h[c.name]
h.delete(c.name)
end
else
h[c.name]=c
end
}
Maintenant, le Hash h
contient les objets sans problème la fusion et le hachage problems
contient ceux qui a des variables d'instance qui diffère.
>> h
=> {"Gorgonzola"=>#<Cheese:0xb375e8 @name="Gorgonzola", @weight=250, @expire_date=#<Date: 2010-12-17 (4911095/2,0,2299161)>>}
>> problems
=> {"Stilton"=>[#<Cheese:0xf54c30 @name="Stilton", @weight=210, @expire_date=#<Date: 2010-12-02 (4911065/2,0,2299161)>>, #<Cheese:0xfdeca8 @name="Stilton", @weight=250,@expire_date=#<Date: 2010-12-02 (4911065/2,0,2299161)>>]}
Pour autant que je peux voir vous ne serez pas avoir à modifier ce code à tout pour soutenir un tableau de UserInfo
objets.
Il serait très probablement beaucoup plus rapide de comparer les propriétés directement ou avec une priorité de ==
. Voici comment passer outre ==
def ==(other)
return self.weight == other.weight && self.expire_date == other.expire_date
end
et la boucle change dans ce
arr.each {|c|
if h.has_key?(c.name)
if problems.has_key?(c.name)
problems[c.name]=problems[c.name]<<c
elsif h[c.name] != c
problems[c.name]=problems[c.name]<<c<<h[c.name]
h.delete(c.name)
end
else
h[c.name]=c
end
}
Enfin, vous pouvez convertir le Hash
retour à un Array
result = h.values
Vous utilisez la fusion de verbes, lorsque vous voulez vraiment supprimer des doublons. Vous avez aussi tagué ceci avec 'hash' quand vous posez des questions sur les tableaux. Vous devriez probablement éditer cette question pour la rendre plus claire. – Olly
@Olly: modification de la balise de 'hash' en 'arrays'. –