2014-06-13 6 views
0

Quelle est la façon la plus concise de convertir ceci:Utiliser la programmation fonctionnelle pour effectuer une transformation sur chaque élément dans un hachage

{ 
    "AT"=>"de-DE", 
    "DE"=>"de-DE", 
    "LI"=>"de-DE" 
} 

à cela?

{ 
    "AT"=>"de", 
    "DE"=>"de", 
    "LI"=>"de" 
} 

Je ne peux pas voir un moyen de le faire avec Hash.map. Je ne veux pas créer de variable temporaire ou muter le hachage initial.

+0

Ceci est un site de Q & A ... Qu'est-ce qui ne va pas avec «pêcher pour les réponses» exactement? –

+0

Lire http://stackoverflow.com/help/on-topic, en particulier # 3 dans la liste, avec http://meta.stackexchange.com/questions/156810/stack-overflow-question-checklist. Stack Overflow est Q & A oui, mais ce n'est pas une question. Il y en a qui sont hors sujet, et la FAQ explique cela. –

Répondre

2
Hash[h.map{|k,v| [k,v[0..1]]}] 
+0

Mieux - donc vous passez d'un tableau de tableaux à un hachage, mais n'y a-t-il pas un moyen plus direct de le faire? –

+0

Ok J'accepte celui-ci pour l'instant mais croisant mes doigts qu'il y a quelque chose de secret intégré dans 'Hash.map' ou une autre fonction ou bibliothèque qui le fait sans passer par un tableau imbriqué. –

+4

Il n'y a pas de 'Hash # map'. Il n'y a que 'Enumerable # map', et toutes les méthodes de transformation' Enumerable' retournent toujours 'Array's. –

1

Je ferais

hash = { 
    "AT"=>"de-DE", 
    "DE"=>"de-DE", 
    "LI"=>"de-DE" 
} 

Hash[hash.map { |k,v| [k,v[/(.*?)-/,1]] }] 
# => {"AT"=>"de", "DE"=>"de", "LI"=>"de"} 

Une autre façon: -

hash.each_with_object({}) { |(k, v), h| h[k] = v[/(.*?)-/,1] } 
# => {"AT"=>"de", "DE"=>"de", "LI"=>"de"} 
+0

J'ai clarifié ma question pour montrer que je veux éviter une variable temporaire ou muter mon hash original. Je veux juste créer un nouveau hachage avec des valeurs modifiées en ligne. –

+0

@MichaelForrest Rien que j'ai détruit .. Le précédent est revenu .. :-) –

+1

Petit point, j'utiliserais '/(.*?)-/' juste au cas où il y aurait d'autres cas où il y a plus d'un tiret (paresseux est généralement préférable). Évidemment, cela n'a pas d'importance dans ce cas. –

0

Peut-être que cela fonctionnera

p = Hash.new 
{"AT"=>"de-DE", "DE" => "de-DE", "LI" => "de-DE" }.each{ |k,v| p[k] = v.split('-')[0] } 
0

Cela ne crée pas un objet intermédiaire autre que le hachage et les chaînes qui apparaissent dans le résultat.

{ 
    "AT"=>"de-DE", 
    "DE"=>"de-DE", 
    "LI"=>"de-DE" 
} 
.keys.each_with_object({}){|k, h| h[k] = "de"} 
+0

En ce qui concerne la création d'un objet intermédiaire, n'avez-vous pas besoin de 'each_key' plutôt que de' keys'? Si le littéral de chaîne "de" est donné, ce qui semble une interprétation raisonnable de la question, et que les objets intermédiaires étaient autorisés, nous pourrions faire 'h.keys.product ([" de "]). To_h'. (Oui, pas le point de la question.) –

2
h = { 
    "AT"=>"de-DE", 
    "DE"=>"de-DE", 
    "LI"=>"de-DE" 
} 
p result = h.each_with_object({}){|(k,v), res| res[k] = v[0,2] } 
# => {"AT"=>"de", "DE"=>"de", "LI"=>"de"} 
1

Étant donné une version assez récente de Ruby, ce fait le tour et "lit avant" comme vous voulez:

h.map { |k,v| [k, v[0..1]] }.to_h 
#=> {"AT"=>"de", "DE"=>"de", "LI"=>"de"} 
0

est ici un déguisé Enumerable#each_with_object qui utilise Object#tap (Ruby v1. 9+):

h = { "AT"=>"de-DE", "DE"=>"de-DE", "LI"=>"de-DE" } 

{}.tap { |g| h.each_key { |k| g[k] = h[k][/[a-z]+/] } } 
    #=> {"AT"=>"de", "DE"=>"de", "LI"=>"de"} 
Questions connexes