Double Possible:
Comment comparer les deux hachages?J'ai deux rubis hachages (qui sont essentiellement des modèles) et suis en train d'essayer de trouver les différences entre eux, l'un est une ancienne instance d'un objet où l'autre a de nouvelles valeurs attribuées à certains attributs. Je suis en train de déterminer les touches ont changé, mais il ne semble pas être quelque chose de construit dans la table de Hachage pour cela. Je ne peux penser à quelques brute forceish solutions, mais je me demandais si il n'y a peut-être une solution élégante là-bas.
Idéalement, j'ai besoin d'être capable de prendre deux hashs de la sorte:
element1 = {:name => "Original", :description => "The original one!"} element2 = {:name => "Original", :description => "The new one!"}
Et être en mesure de comparer/diff et pour obtenir quelque chose comme ceci:
{:description => "The new one!"}
Maintenant tout ce que je peux penser à est de l'itération sur les touches dans l'un de hachage et en comparant la valeur de la clé à la clé correspondante dans le second hachage, mais qui semble trop brutale forcé.
Des idées? Merci beaucoup!
Réponses
Trop de publicités?voici une version légèrement modifiée de colin.
class Hash
def diff(other)
(self.keys + other.keys).uniq.inject({}) do |memo, key|
unless self[key] == other[key]
if self[key].kind_of?(Hash) && other[key].kind_of?(Hash)
memo[key] = self[key].diff(other[key])
else
memo[key] = [self[key], other[key]]
end
end
memo
end
end
end
Elle explore les codes de hachage pour une plus grande efficacité à gauche et à droite
{a: {c: 1, b: 2}, b: 2}.diff({a: {c: 2, b: 2}})
retourne
{:a=>{:c=>[1, 2]}, :b=>[2, nil]}
au lieu de
{:a=>[{:c=>1, :b=>2}, {:c=>2, :b=>2}], :b=>[2, nil]}
Excellente idée colin
voici comment faire pour appliquer les changements à l'origine de hachages
def apply_diff!(changes, direction = :right)
path = [[self, changes]]
pos, local_changes = path.pop
while local_changes
local_changes.each_pair {|key, change|
if change.kind_of?(Array)
pos[key] = (direction == :right) ? change[1] : change[0]
else
path.push([pos[key], change])
end
}
pos, local_changes = path.pop
end
self
end
def apply_diff(changes, direction = :right)
cloned = self.clone
path = [[cloned, changes]]
pos, local_changes = path.pop
while local_changes
local_changes.each_pair {|key, change|
if change.kind_of?(Array)
pos[key] = (direction == :right) ? change[1] : change[0]
else
pos[key] = pos[key].clone
path.push([pos[key], change])
end
}
pos, local_changes = path.pop
end
cloned
end
donc, pour le faire ressembler le droit d'exécuter
{a: {c: 1, b: 2}, b: 2}.apply_diff({:a=>{:c=>[1, 2]}, :b=>[2, nil]})
pour obtenir
{a: {c: 2, b: 2}, b: nil}
pour obtenir exacte, nous aurions aller un peu plus loin et d'enregistrer une différence entre entre le néant et pas de clé
et il serait bien aussi de raccourcir long de tableaux en fournissant seulement ajoute et supprime
J'ai trouvé la méthode diff de Rails 'Hash pour ne pas vraiment me dire ce qu'il y avait du côté gauche et du côté droit (ce qui est beaucoup plus utile). Il y avait un plugin appelé "Riff", qui a depuis disparu, qui vous permettrait de différencier deux objets ActiveRecord. Essentiellement:
class Hash
def diff(other)
self.keys.inject({}) do |memo, key|
unless self[key] == other[key]
memo[key] = [self[key], other[key]]
end
memo
end
end
end