32 votes

Comparaison des hachages rubis

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!

34voto

Pete Brumm Points 714

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

20voto

Colin Curtin Points 1087

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
 

11voto

glenn mcdonald Points 8933

Si tout ce qui vous intéresse est ce qui est unique dans element2, vous pouvez simplement faire:

 element2.to_a - element1.to_a
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X