2010-07-27 10 views
1
[ 
    { 
     "name": "John Doe", 
     "location": { 
      "name": "New York, New York", 
      "id": 12746342329 
     }, 
     "hometown": { 
      "name": "Brooklyn, New York", 
      "id": 43453644 
     } 
    }, 
    { 
     "name": "Jane Doe", 
     "location": { 
      "name": "Miami, Florida", 
      "id": 12746342329 
     }, 
     "hometown": { 
      "name": "Queens, New York", 
      "id": 12746329 
     } 
    } 
] 

Étant donné ce morceau de JSON, comment serais-je capable de faire défiler et de sortir toutes les clés "ville natale" et "emplacement" et de voir quelles personnes avaient la valeur de Nouveau York?Comparer plusieurs valeurs dans un tableau Ruby

Mon problème est que je peux Array.each à travers ces articles, mais je ne sais pas comment traverser à la fois l'emplacement & & ville d'origine avec mes critères ("New York").

+0

ce qui a été mis à jour – kylemac

Répondre

4
people.select {|person| 
    person.any? {|k, v| 
    %w[location hometown].include?(k) && /New York/ =~ v['name'] 
}} 

Ceci dit essentiellement ce qui suit: sélectionnez toutes les entrées dans le tableau pour lequel la condition suivante est vraie. La condition est: est-il vrai pour l'une des paires clé-valeur que la clé est 'hometown' ou 'location' et la propriété name de la valeur appartenant à cette clé correspond à l'expression rationnelle /New York/? Toutefois, votre modèle d'objet semble avoir sérieusement besoin d'être refactorisé. En fait, le problème principal est que votre modèle d'objet n'est même pas un modèle d'objet, c'est un modèle de hachage et de tableau.

Voici ce que je veux dire par un modèle d'objet propre:

class Person 
    attr_reader :name, :location, :hometown 

    def initialize(name, location=nil, hometown=nil) 
    @name, @location, @hometown = name, location, hometown 
    end 

    def cities 
    return @location, @hometown 
    end 
end 

class City 
    attr_reader :id, :name 

    def initialize(id, name) 
    @id, @name = id, name 
    end 

    def =~(other) 
    name =~ other 
    end 
end 

nyc = City.new(12746342329, 'New York, New York') 
brooklyn = City.new(43453644, 'Brooklyn, New York') 
miami = City.new(12746342329, 'Miami, Florida') 
queens = City.new(12746329, 'Queens, New York') 

john = Person.new('John Doe', nyc, brooklyn) 
jane = Person.new('Jane Doe', miami, queens) 

people = [john, jane] 

Si vous avez un tel modèle d'objet propre, votre code devient beaucoup plus propre, car au lieu de taquineries à part les noix de Bults d'un labyrinthe imbriquée hash et les tableaux, vous avez de bons petits objets que vous pouvez simplement poser quelques questions:

people.select {|person| person.cities.any? {|city| city =~ /New York/ }} 

vous pouvez presque lire cela comme l'anglais: à partir du tableau sélectionner toutes les personnes pour lesquelles correspond à la Regexp /New York/ une de leurs villes.

Si nous améliorons le modèle d'objet plus loin, il y a encore mieux:

class Person 
    def lived_in?(pattern) 
    cities.any? {|city| city =~ pattern } 
    end 
end 

people.select {|person| person.lived_in?(/New York/) } 

Cela dit essentiellement « du peuple, sélectionnez ceux qui à un moment vécu à New York ». C'est beaucoup mieux que "des personnes sélectionnent tout pour lequel le premier élément de la paire valeur clé est soit la chaîne 'hometown' ou la chaîne 'location' et le deuxième élément de la paire de valeurs clés correspond à l'expression rationnelle /New York/".

+0

J'ai mis à jour le JSON pour être valide, ne vous dérangerait lui donner un autre regard? – kylemac

+0

@kylemac: ça marche. –

+0

ça vous dérange d'expliquer ce qui se passe ici? Je suis nouveau à ruby ​​et c'est un peu sur ma tête – kylemac

1

Je pense que la solution de Jörg a un bug mineur - « lieu » et « ville natale » ne sont pas utilisés, ainsi, par exemple, suite à « personne » passerait le test:

{ 
    'name' => 'Foo Bar', 
    'favourite movie' => { 
    name => 'New York, New York!' 
    } 
} 

Voici un coup de feu à corriger elle, ainsi que les commentaires:

ary.select {|person| # get me every person satisfying following condition 
    %w[location hometown].any? {|key| # check if for any of the strings 'location' and 'hometown' 
    # person should have that key, and its 'name' should contain /New York/ regexp 
    person[key] && person[key]['name'] && /New York/ =~ person[key]['name'] 
}} 
+0

+1, Merci de l'avoir remarqué. Bigfoot majeur de ma part.Je me suis vraiment souvenu d'ajouter une personne de Chicago au test, afin que je puisse déterminer si le filtre fonctionnait * du tout * mais j'ai complètement manqué * ce * cas particulier. Bon travail! (Oh, et Yay pour les IDE!) Si j'avais tapé ce code dans mon favori personnel, NetBeans, au lieu du stupide StackOverflow WYSIWIG éditeur et IRB, il aurait immédiatement mis en évidence les deux comme "variables locales inutilisées".) –

Questions connexes