J'essaie d'obtenir un sous-ensemble de clés pour chaque hachage d'un tableau.
Les hachages sont en réalité beaucoup plus gros, mais je me suis dit que c'était plus facile à comprendre:
[
{
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
}
]
Je veux obtenir uniquement les valeurs id
et start
.
J'ai essayé:
return_keys = ['id','start']
return_array = events.select{|key,val| key.to_s.in? return_keys}
mais cela retourne un tableau vide.
Cela devrait faire ce que vous voulez:
events.map do |hash|
hash.select do |key, value|
[:id, :start].include? key
end
end
Solution potentiellement plus rapide (mais un peu moins jolie):
events.map do |hash|
{ id: hash[:id], start: hash[:start] }
end
Si vous avez besoin de return_keys
pour être dynamique:
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
Notez que, dans votre code, select
choisit des éléments dans array, puisque vous l'appelez ainsi, mais ne change pas les hachages contenus dans le tableau.
Si vous êtes préoccupé par les performances, j'ai analysé toutes les solutions répertoriées ici ( code ):
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)
S'il vous arrive d'utiliser Rails (ou si vous avez intérêt à intégrer tout ou partie d'ActiveSupport), vous pouvez utiliser Hash#slice
:
return_array = events.map { |h| h.slice(:id, :start) }
Hash#slice
fait un peu plus de travail sous les couvertures, mais il est probablement assez rapide pour ne pas le remarquer pour les petits hachages et la clarté est plutôt agréable.
Une meilleure solution consiste à utiliser un hachage comme index au lieu d'effectuer une recherche de tableau linéaire pour chaque clé:
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"}]
J'ai ajusté cette option pour utiliser des symboles en tant que noms de clé correspondant à votre définition de events
.
Cela peut être encore amélioré en utilisant le return_keys
en tant que pilote direct:
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
Le résultat est le même. Si le sous-ensemble que vous extrayez a tendance à être beaucoup plus petit que l'original, c'est peut-être la meilleure approche.
Considérant que l'efficacité semble être une préoccupation, je suggérerais ce qui suit.
Code
require 'set'
def keep_keys(arr, keeper_keys)
keepers = keeper_keys.to_set
arr.map { |h| h.select { |k,_| keepers.include?(k) } }
end
Ceci utilise Hash # select , qui, contrairement à Enumerable # select , renvoie un hachage. J'ai converti keeper_keys
en un ensemble permettant des recherches rapides.
Exemples
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]