2017-12-05 3 views
0

Ich habe ein Array von Hashes, von denen jede nicht-normierten Werte wie folgt hat:Suche Array von unterschiedlichen Hashes

arr = [{ 
    id: 0, 
    type: 'character', 
    person: { 
     name: 'Steve Rogers', 
     weapon: 'Shield', 
     known: true 
    } 
    }, 
    { 
    id: 1, 
    type: 'organization', 
    company: "Pym Industries", 
    tech: 'Shrinking suit' 
    }, 
    { 
    id: 2, 
    type: 'character', 
    person: { 
     name: 'Tony Stark', 
     weapon: 'Ironman Suit', 
     known: false 
    } 
    }] 

Einige der Hashwerte unterschiedlich sind. Ich möchte eine Untergruppe von Hashes erhalten, deren Person ich kenne, d. H. arr.person.known ist true. Das Ergebnis sollte wie:

subarr = [{ 
    id: 0, 
    type: 'character', 
    person: { 
     name: 'Steve Rogers', 
     weapon: 'Shield', 
     known: true 
    } 
    }] 

Ich habe versucht:

b = arr.select{|x| x.person.known} 
b = arr.reject{|x| if x.person then x.person.known} 

Aber treffe ich NoMethodError: undefined method `person' for Hash:0x007fc5f6f587f0.

+0

Beachten Sie, dass 'arr [ 'Person']' und 'arr.person' ist die gleiche Sache in JavaScript, aber nicht in Ruby. Ein Hash ist nicht dasselbe wie ein Objekt. Es gibt Dinge, die Sie tun können, damit sich Ruby-Hash auf diese Weise verhält, aber es wird nicht empfohlen, da dies sowohl subtile als auch nicht so subtile Fehler verursachen kann. – Amadan

+0

@Amadan Verstehen Sie das. Ich arbeite tatsächlich mit verbundenen Aufzeichnungen in Schienen. Wo jeder Eintrag has_one Person und eine Person gehört_to: Eintrag, inverse_of:: Eintrag, optional: true – RedOster

+0

Sie sagten "Array von Hashes", getaggt als "Hash" ... Wenn Sie tatsächlich ein Array von Objekten haben, 'arr. Wählen Sie {| x | x & .person & .known} 'ist am deutlichsten. – Amadan

Antwort

6

Versuchen Sie dieses

arr.select { |item| item.fetch(:person, {})[:known] } 

oder

arr.select { |item| (item[:person] || {})[:known] } 

oder von Ruby 2.3.0

arr.select { |item| item.dig(:person, :known) } 

Wortreicher aber vielleicht klarer

arr.select do |item| 
    person = item.fetch(:person, {}) 
    person[:known] 
end 

oder

arr.select { |item| item[:person] && item[:person][:known] } 
+1

Oder sogar 'arr.select {| x | x [: person] &. [] (: bekannt)} '(aber' dig' ist wirklich nett). – Amadan

+0

Oder das. Aber ich denke, es gibt genug Möglichkeiten: D – Ursus