2010-09-21 4 views
4

J'utilise ruby ​​1.8.7 et j'ai besoin de comparer deux hachages que j'ai, qui sont essentiellement les attributs d'un modèle. Hash A est plus petit que Hash B, et Hash B possède tous les attributs de hash A, plus quelques attributs supplémentaires dont je ne me soucie pas. Mon objectif principal est de voir si les éléments de A sont les mêmes que les éléments respectifs de B. Ainsi, par exempleComparer deux hachages similaires en ruby ​​

@hash_a = {:cat => 'Bubby', :dog => 'Gizmo'} 
@hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
@hash_a == @hash_b 
#=> true 

Maintenant, il devient un peu plus compliqué que cela, car les champs ne correspondent pas complètement , même si elles référances la même information

@hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'} 
@hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
@hash_a == @hash_b 
#=> true 

Qu'est-ce que je travaille est un processus qui compare deux éléments correspondants, il met à jour si les champs ont changé, et seulement si elles changé. Ou crée un nouvel article s'il ne trouve pas un article correspondant. Changer les noms du hachage lui-même n'est pas une option. Actuellement, je ne fais que comparer chaque champ dans une méthode privée pour voir s'ils sont égaux. Je pense qu'il doit y avoir un meilleur moyen, je suis à la recherche de quelque chose de plus rapide et plus élégant que celui-ci.

+0

Qu'essayez-vous de réaliser? Simplicité du code de comparaison? Efficacité/vitesse? – GreyCat

Répondre

0

Une possibilité est d'abord remapper les clés d'un hachage, puis effectuer une opération de sous-ensemble de jeu:

require 'set' 

def remap_keys(hash, key_map) 
    hash.inject({}) do |acc, pair| 
    key, value = pair 
    remapped_key = key_map[key] || key 
    acc[remapped_key] = value 
    acc 
    end 
end 

def hash_subset?(a, b) 
    set_a = Set.new(a) 
    set_b = Set.new(b) 
    set_a.subset?(set_b) 
end 

hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'} 
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 

puts hash_subset?(remap_keys(hash_a, {:cats_name => :cat}), hash_b) 

Cependant, je suis sûr qu'il ya des moyens plus efficaces de le faire. Plus d'une façon de peau un :cat, hein ?!

1

Heh, si vous vraiment voulez rapide et élégant, ici vous allez:

(a = @hash_a.values; (a & @hash_b.values) == a) 

Il y a certaines limites évidentes ...

+0

n'est-ce pas ignorer les touches cependant? si {: cat => 'Gizmo',: chien => 'Bubby'} – Mysrt

+0

Si, c'est la "limitation". – DigitalRoss

+0

Oh, et vous pourriez avoir besoin de trier les résultats, même si cela n'était pas nécessaire avec vos données d'exemple. – DigitalRoss

1

Voici comment je le ferais:

def eql hash1, hash2, rewire = {} 
    map = Hash.new {|h, key| rewire[key] || key} 
    !hash1.any? do |key, val| 
    hash2[map[key]] != val 
    end 
end 


hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'} 
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
p eql(hash_a, hash_b) #=> false 

hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'} 
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
p eql(hash_a, hash_b, :cats_name => :cat) #=> true 


hash_a = {:cat => 'Bubby', :dog => 'Gizmo'} 
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
p eql(hash_a, hash_b) #=> true 

hash_a = {:cat => 'Bubby', :dog => 'Gizmo', :fish => "Wanda"} 
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'} 
p eql(hash_a, hash_b) #=> false 

Pas trop longtemps, et qui semble fonctionner comme vous le voulez aussi :)

3

Si vous convertissez les hachages en tableau, vous pouvez les comparer comme ceci.

@hash_a.to_a == (@hash_a.to_a & @hash_b.to_a) 

Vous pouvez également cacher ce code derrière une méthode dans la classe de hachage si vous voulez:

class Hash 
    def diff_equal(other) 
    to_a == (to_a & other.to_a) 
    end 
end 

utiliser ensuite comme @hash_a.diff_equal(@hash_b). Si vous avez choisi ce chemin, vous pouvez vérifier que l'autre est un hachage ou répond à la méthode to_a.

+0

Cela peut être encore simplifié. (a-b) retourne un tableau vide si a est un sous-ensemble de b. http://stackoverflow.com/a/3897535/566878 – Ankush