Ich versuche, eine Teilmenge von Schlüsseln für jeden Hash in einem Array abzurufen.
Die Hashes sind tatsächlich viel größer, aber ich dachte, das ist einfacher zu verstehen:
[
{
id:2,
start: "3:30",
break: 30,
num_attendees: 14
},
{
id: 3,
start: "3: 40",
break: 40,
num_attendees: 4
},
{
id: 4,
start: "4: 40",
break: 10,
num_attendees: 40
}
]
Ich möchte nur die Werte id
und start
erhalten.
Ich habe es versucht:
return_keys = ['id','start']
return_array = events.select{|key,val| key.to_s.in? return_keys}
dies gibt jedoch ein leeres Array zurück.
Dies sollte tun, was Sie wollen:
events.map do |hash|
hash.select do |key, value|
[:id, :start].include? key
end
end
Möglicherweise schnellere (aber etwas weniger hübsche) Lösung:
events.map do |hash|
{ id: hash[:id], start: hash[:start] }
end
Wenn Sie return_keys
benötigen, um dynamisch zu sein:
return_keys = [:id, :start]
events.map do |hash|
{}.tap do |new_hash|
return_keys.each do |key|
new_hash[key] = hash[key]
end
end
end
Beachten Sie, dass select
in Ihrem Code Elemente aus dem array auswählt, da Sie dies so bezeichnet haben, die im Array enthaltenen Hashes jedoch nicht ändern.
Wenn Sie über die Leistung besorgt sind, habe ich alle hier aufgeführten Lösungen ( code ) bewertet:
user system total real
amarshall 1 0.140000 0.000000 0.140000 ( 0.140316)
amarshall 2 0.060000 0.000000 0.060000 ( 0.066409)
amarshall 3 0.100000 0.000000 0.100000 ( 0.101469)
tadman 1 0.140000 0.010000 0.150000 ( 0.145489)
tadman 2 0.110000 0.000000 0.110000 ( 0.111838)
mu 0.130000 0.000000 0.130000 ( 0.128688)
Wenn Sie Rails verwenden (oder nichts dagegen haben, ActiveSupport ganz oder teilweise einzubeziehen), können Sie Hash#slice
verwenden:
return_array = events.map { |h| h.slice(:id, :start) }
Hash#slice
leistet zusätzliche Arbeit unter der Decke, aber es ist wahrscheinlich schnell genug, dass Sie es für kleine Hashes nicht bemerken werden und die Klarheit ist ganz nett.
Eine bessere Lösung ist, einen Hash als Index zu verwenden, anstatt für jeden Schlüssel eine lineare Array-Suche durchzuführen:
events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]
return_keys = [ :id, :start ]
# Compute a quick hash to extract the right values: { key => true }
key_index = Hash[return_keys.collect { |key| [ key, true ] }]
return_array = events.collect do |event|
event.select do |key, value|
key_index[key]
end
end
# => [{:id=>2, :start=>"3:30"}, {:id=>3, :start=>"3:40"}, {:id=>4, :start=>"4:40"}]
Ich habe dies so eingestellt, dass Symbole als Schlüsselnamen verwendet werden, die Ihrer Definition von events
entsprechen.
Dies kann weiter verbessert werden, indem der return_keys
als direkter Treiber verwendet wird:
events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]
return_keys = [ :id, :start ]
return_array = events.collect do |event|
Hash[
return_keys.collect do |key|
[ key, event[key] ]
end
]
end
Das Ergebnis ist das gleiche. Wenn die extrahierte Teilmenge tendenziell viel kleiner als das Original ist, ist dies möglicherweise die beste Vorgehensweise.
In Anbetracht dessen, dass die Effizienz ein Problem zu sein scheint, würde ich folgendes vorschlagen.
Code
require 'set'
def keep_keys(arr, keeper_keys)
keepers = keeper_keys.to_set
arr.map { |h| h.select { |k,_| keepers.include?(k) } }
end
Dies verwendet Hash # select , was im Gegensatz zu Enumerable # select einen Hash zurückgibt. Ich habe keeper_keys
in einen Satz für schnelle Suchvorgänge konvertiert.
Beispiele
arr = [{ id:2, start: "3:30", break: 30 },
{ id: 3, break: 40, num_attendees: 4 },
{ break: 10, num_attendees: 40 }]
keep_keys arr, [:id, :start]
#=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}]
keep_keys arr, [:start, :break]
#=> [{:start=>"3:30", :break=>30}, {:break=>40}, {:break=>10}]
keep_keys arr, [:id, :start, :cat]
#=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}]
keep_keys arr, [:start]
#=> [{:start=>"3:30"}, {}, {}]
keep_keys arr, [:cat, :dog]