J’ai un hash qui ressemble à ceci:
params = { :irrelevant => "A Ssortingng", :choice1 => "Oh look, another one", :choice2 => "Even more ssortingngs", :choice3 => "But wait", :irrelevant2 => "The last ssortingng" }
Et je veux un moyen simple de rejeter toutes les clés qui ne sont pas choisies + int. Cela pourrait être choix1, ou choix1 par choix10. Cela varie.
Comment puis-je isoler les touches avec juste le choix du mot et un chiffre ou des chiffres après eux?
Prime:
Tournez le hachage dans une chaîne avec l’onglet (\ t) en tant que délimiteur. Je l’ai fait, mais il a fallu plusieurs lignes de code. Habituellement, les maîtres Rubicians peuvent le faire en une ou plusieurs lignes.
REMARQUE: Si vous utilisez Rails, vous pouvez utiliser Hash.slice
comme indiqué par lfx_cool dans la réponse ci-dessous.
Si vous utilisez Ruby, vous pouvez utiliser la méthode select
. Vous devrez convertir la clé d’un symbole en chaîne pour effectuer la correspondance avec l’expression rationnelle. Cela vous donnera un nouveau Hash avec juste les choix.
choices = params.select { |key, value| key.to_s.match(/^choice\d+/) }
ou vous pouvez utiliser delete_if
et modifier le Hash existant, par exemple
params.delete_if { |key, value| !key.to_s.match(/choice\d+/) }
ou si ce ne sont que les clés et non les valeurs que vous voulez, alors vous pouvez faire:
params.keys.select { |key| key.to_s.match(/^choice\d+/) }
et cela donnera le juste un tableau des clés, par exemple [:choice1, :choice2, :choice3]
Dans Ruby, la sélection Hash # est une bonne option. Si vous travaillez avec Rails, vous pouvez utiliser Hash # slice et Hash # slice !. par exemple (rails 3.2.13)
h1 = {:a => 1, :b => 2, :c => 3, :d => 4} h1.slice(:a, :b) # return {:a=>1, :b=>2}, but h1 is not changed h2 = h1.slice!(:a, :b) # h1 = {:a=>1, :b=>2}, h2 = {:c => 3, :d => 4}
Le moyen le plus simple consiste à inclure la gem 'activesupport'
(ou gem 'active_support'
).
Ensuite, dans votre classe, il vous suffit de
require 'active_support/core_ext/hash/slice'
et d’appeler
params.slice(:choice1, :choice2, :choice3) # => {:choice1=>"Oh look, another one", :choice2=>"Even more ssortingngs", :choice3=>"But wait"}
Je crois que cela ne vaut pas la peine de déclarer d’autres fonctions susceptibles d’avoir des bogues, et il est préférable d’utiliser une méthode qui a été modifiée au cours des dernières années.
Le moyen le plus simple consiste à inclure la gem ‘ActiveSupport’ (ou gem ‘active_support’).
params.slice(:choice1, :choice2, :choice3)
Ceci est une ligne pour résoudre la question originale complète:
params.select { |k,_| k[/choice/]}.values.join('\t')
Mais la plupart des solutions ci-dessus résolvent un cas où vous devez connaître les clés à l’avance, en utilisant slice
ou simple regexp.
Voici une autre approche qui fonctionne pour des cas d’utilisation simples et plus complexes, qui est permutable à l’exécution
data = {} matcher = ->(key,value) { COMPLEX LOGIC HERE } data.select(&matcher)
Désormais, non seulement cela permet une logique plus complexe pour faire correspondre les clés ou les valeurs, mais elle est également plus facile à tester et vous pouvez échanger la logique correspondante à l’exécution.
Ex pour résoudre le problème d’origine:
def some_method(hash, matcher) hash.select(&matcher).values.join('\t') end params = { :irrelevant => "A Ssortingng", :choice1 => "Oh look, another one", :choice2 => "Even more ssortingngs", :choice3 => "But wait", :irrelevant2 => "The last ssortingng" } some_method(params, ->(k,_) { k[/choice/]}) # => "Oh look, another one\\tEven more ssortingngs\\tBut wait" some_method(params, ->(_,v) { v[/ssortingng/]}) # => "Even more ssortingngs\\tThe last ssortingng"
Si vous travaillez avec des rails et que vous avez les clés dans une liste séparée, vous pouvez utiliser la notation *
:
keys = [:foo, :bar] hash1 = {foo: 1, bar:2, baz: 3} hash2 = hash1.slice(*keys) => {foo: 1, bar:2}
Comme d’autres réponses l’ont indiqué, vous pouvez également utiliser la slice!
pour modifier le hachage en place (et renvoyer la clé / les valeurs effacées).
Mettez ceci dans un initialiseur
class Hash def filter(*args) return nil if args.try(:empty?) if args.size == 1 args[0] = args[0].to_s if args[0].is_a?(Symbol) self.select {|key| key.to_s.match(args.first) } else self.select {|key| args.include?(key)} end end end
Alors tu peux faire
{a: "1", b: "b", c: "c", d: "d"}.filter(:a, :b) # => {a: "1", b: "b"}
ou
{a: "1", b: "b", c: "c", d: "d"}.filter(/^a/) # => {a: "1"}
Avec Hash::select
:
params = params.select { |key, value| /^choice\d+$/.match(key.to_s) }
Si vous voulez le hachage restant:
params.delete_if {|k, v| ! k.match(/choice[0-9]+/)}
ou si vous voulez juste les clés:
params.keys.delete_if {|k| ! k.match(/choice[0-9]+/)}
params.select{ |k,v| k =~ /choice\d/ }.map{ |k,v| v}.join("\t")
En ce qui concerne la question bonus:
Si vous avez #select
méthode #select
comme ceci (liste des tableaux à 2 éléments):
[[:choice1, "Oh look, another one"], [:choice2, "Even more ssortingngs"], [:choice3, "But wait"]]
puis prenez simplement ce résultat et exécutez:
filtered_params.join("\t") # or if you want only values instead of pairs key-value filtered_params.map(&:last).join("\t")
Si vous avez #delete_if
méthode #delete_if
comme ceci (hash):
{:choice1=>"Oh look, another one", :choice2=>"Even more ssortingngs", :choice3=>"But wait"}
puis:
filtered_params.to_a.join("\t") # or filtered_params.values.join("\t")
params = { :irrelevant => "A Ssortingng", :choice1 => "Oh look, another one", :choice2 => "Even more ssortingngs", :choice3 => "But wait", :irrelevant2 => "The last ssortingng" } choices = params.select { |key, value| key.to_s[/^choice\d+/] } #=> {:choice1=>"Oh look, another one", :choice2=>"Even more ssortingngs", :choice3=>"But wait"}