J'utilise Ruby on Rails 3.0.10 et je voudrais construire une paire clé de hachage\valeur de manière conditionnelle. Autrement dit, j'aimerais ajouter une clé et sa valeur associée si une condition est remplie:
hash = {
:key1 => value1,
:key2 => value2, # This key2\value2 pair should be added only 'if condition' is 'true'
:key3 => value3,
...
}
Comment puis-je faire cela et garder une "bonne" lisibilité pour le code? Suis-je "obligé" d'utiliser la méthode merge
?
Je préfère tap
, car je pense que cela fournit une solution plus propre que celles décrites ici, en ne nécessitant aucune suppression d'éléments compliqués et en définissant clairement la portée dans laquelle le hachage est construit.
Cela signifie également que vous n'avez pas besoin de déclarer une variable locale inutile, ce que je déteste toujours.
Si vous ne l’avez pas déjà rencontrée auparavant, tap
est très simple: c’est une méthode sur Object
qui accepte un bloc et retourne toujours l’objet sur lequel il a été appelé. Donc, pour construire un hash conditionnellement, vous pouvez faire ceci:
Hash.new.tap do |my_hash|
my_hash[:x] = 1 if condition_1
my_hash[:y] = 2 if condition_2
...
end
Il y a beaucoup d'utilisations intéressantes pour tap
, ceci n'en est qu'un.
Une approche fonctionnelle:
hash = {
:key1 => 1,
:key2 => (2 if condition),
:key3 => 3,
}.compact
Remarque: pour Ruby <2.4.0 ou n'utilisant pas active-support, remplacez .compact
par .reject { |k, v| v.nil? }
.
Il est probablement préférable de garder les choses simples si vous êtes préoccupé par la lisibilité:
hsh = {}
hsh[:key1] = value1
hsh[:key2] = value2 if condition?
hsh[:key3] = value3
...
J'utilise merge
et l'opérateur ternaire pour cette situation,
hash = {
:key1 => value1,
:key3 => value3,
...
}.merge(condition ? {:key2 => value2} : {})
Rester simple:
hash = {
:key1 => value1,
:key3 => value3,
...
}
hash[:key2]=value2 if condition
De cette façon, vous séparez aussi visuellement votre cas spécial, ce qui peut passer inaperçu s'il est enterré dans une assignation de hachage.
Commencez par construire votre hash ainsi:
hash = {
:key1 => value1,
:key2 => condition ? value2 : :delete_me,
:key3 => value3
}
Ensuite, faites ceci après avoir construit votre hash:
hash.delete_if {|_, v| v == :delete_me}
À moins que votre hash ne soit gelé ou immuable, cela ne garderait que les valeurs présentes.
SI vous construisez du hachage à partir d'une sorte de donnée Enumerable, vous pouvez utiliser inject, par exemple:
raw_data.inject({}){ |a,e| a[e.name] = e.value if expr; a }
Aussi simple que cela:
hash = {
:key1 => value1,
**(condition ? {key2: value2} : {})
}
J'espère que ça aide!
L'utilisation de fetch peut être utile si vous renseignez un hachage à partir d'attributs facultatifs. Regardez cet exemple:
def create_watchable_data(attrs = {})
return WatchableData.new({
id: attrs.fetch(:id, '/catalog/titles/breaking_bad_2_737'),
titles: attrs.fetch(:titles, ['737']),
url: attrs.fetch(:url, 'http://www.netflix.com/shows/breaking_bad/3423432'),
year: attrs.fetch(:year, '1993'),
watchable_type: attrs.fetch(:watchable_type, 'Show'),
season_title: attrs.fetch(:season_title, 'Season 2'),
show_title: attrs.fetch(:id, 'Breaking Bad')
})
end