2012-01-16 15 views
5

Tengo un hash de tamaño aleatorio, que puede tener valores como "100", que me gustaría convertir a enteros. Sé que puedo hacerlo usando value.to_i if value.to_i.to_s == value, pero no estoy seguro de cómo hacerlo de forma recursiva en mi hash, teniendo en cuenta que un valor puede ser una cadena o una matriz (de hashes o de cadenas) u otro hash.Convertir recursivamente todas las cadenas numéricas en enteros en un hash Ruby

+0

Publicar un ejemplo –

+0

Además, respuesta a su pregunta: el uso recursividad con '' #is_kind_of –

+0

'obj.to_i.to_s == obj' parece extraño?. Puede haber diferentes representaciones de cadena para el mismo valor entero, p. Ej. "1_000_000" o "019". –

Respuesta

10

Esta es una implementación recursiva bastante directa (aunque tener que manejar tanto arrays como hashes agrega un poco de trucos).

def fixnumify obj 
    if obj.respond_to? :to_i 
    # If we can cast it to a Fixnum, do it. 
    obj.to_i 

    elsif obj.is_a? Array 
    # If it's an Array, use Enumerable#map to recursively call this method 
    # on each item. 
    obj.map {|item| fixnumify item } 

    elsif obj.is_a? Hash 
    # If it's a Hash, recursively call this method on each value. 
    obj.merge(obj) {|k, val| fixnumify val } 

    else 
    # If for some reason we run into something else, just return 
    # it unmodified; alternatively you could throw an exception. 
    obj 

    end 
end 

Y, oye, incluso funciona:

hsh = { :a => '1', 
     :b => '2', 
     :c => { :d => '3', 
       :e => [ 4, '5', { :f => '6' } ] 
       }, 
     :g => 7, 
     :h => [], 
     :i => {} 
     } 

fixnumify hsh 
# => {:a=>1, :b=>2, :c=>{:d=>3, :e=>[4, 5, {:f=>6}]}, :g=>7, :h=>[], :i=>{}} 
+1

Gracias, eso funciona. Sin embargo, tuve que cambiar el primero si to 'obj.respond_to? : to_i y obj.to_i.to_s == obj' porque mi hash también puede contener cadenas alfabéticas. Puede editar su respuesta en consecuencia. ¡Gracias de nuevo! –

+2

'obj.merge (obj) {| k, val | fixnumify val} '=>' Hash [obj.map {| k, v | [k, fixnumify (val)] '? Solo tengo la corazonada de que puede ser más rápido. –

+0

Eso podría ser, @VictorMoroz, aunque lo adivinaría solo de forma incremental. Siempre me olvido de 'Hash []'. ¡Gracias! –

0

Ésta es mi clase de ayuda. Solo convierte Cadenas que son solo números (Entero o Flotante).

module Helpers 
    class Number 
    class << self 
     def convert(object) 
     case object 
     when String 
      begin 
      numeric(object) 
      rescue StandardError 
      object 
      end 
     when Array 
      object.map { |i| convert i } 
     when Hash 
      object.merge(object) { |_k, v| convert v } 
     else 
      object 
     end 
     end # convert 

     private 

     def numeric(object) 
     Integer(object) 
     rescue 
     Float(object) 
     end # numeric 
    end # << self 
    end # Number 
end # Helpers 

Helpers::Number.convert [{a: ["1", "22sd"]}, 2, ['1.3', {b: "c"}]] 
#=> [{:a=>[1, "22sd"]}, 2, [1.3, {:b=>"c"}]] 
Cuestiones relacionadas