web-dev-qa-db-fra.com

Construire un hash de manière conditionnelle

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?

35
Backo

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.

53
Russell

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? }.

24
tokland

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
...
8
dwhalen

J'utilise merge et l'opérateur ternaire pour cette situation,

hash = {
  :key1 => value1,
  :key3 => value3,
  ...
}.merge(condition ? {:key2 => value2} : {})
3
Dave Morse

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.

3
Mladen Jablanović

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.

2
Chris Jester-Young

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 }
1
Dmitry Maksimov

Aussi simple que cela: 

hash = {
  :key1 => value1,
  **(condition ? {key2: value2} : {})
}

J'espère que ça aide!

1
Dusht

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
0
Excalibur