2012-01-03 19 views
22

tengo un hash como:Rubí DUP/clon de forma recursiva

h = {'name' => 'sayuj', 
    'age' => 22, 
    'project' => {'project_name' => 'abc', 
        'duration' => 'prq'}} 

Necesito un DUP de este hash, el cambio no debe afectar a la original Hash.

Cuando intento,

d = h.dup # or d = h.clone 
d['name'] = 'sayuj1' 
d['project']['duration'] = 'xyz' 

p d #=> {"name"=>"sayuj1", "project"=>{"duration"=>"xyz", "project_name"=>"abc"}, "age"=>22} 
p h #=> {"name"=>"sayuj", "project"=>{"duration"=>"xyz", "project_name"=>"abc"}, "age"=>22} 

Aquí se puede ver la project['duration'] se cambia en el hash original porque project es otro objeto hash.

Quiero que el hash sea duped o cloned recursivamente. ¿Cómo puedo conseguir esto?

Respuesta

39

Así es como hacer copias de profundidad en Rubí

d = Marshal.load(Marshal.dump(h)) 
+2

Esto crea copias completas de todos los objetos referenciados por 'h'. Esto podría ser exactamente lo que necesita Sayuj para simples hash de cadenas. Con objetos más complejos, esto podría no ser deseado más. Una vez podría anular el método 'Hash # dup' para duplicar todos los hash en' values' recursivamente. Pero eso necesitaría extenderse para cada tipo de objeto. –

+2

@HolgerJust: sí, es por eso que se llama una "copia profunda" :-) –

+1

Por supuesto. Solo quería mencionar que podría hacer más de lo que el OP pretendía (aunque probablemente esté bien) :) Así que es solo para, bueno, referencia futura. –

1

Ésta es una respuesta a una pregunta bastante viejo, pero me encontré con que al aplicar algo similar, pensó Yo interrumpiría de un método más eficiente .

Por la sencilla profunda hachís, dos niveles como el anterior, también se puede hacer algo como esto:

d = h.inject({}) {|copy, (key, value)| 
    copy[key] = value.dup rescue value; copy 
} 

me hizo una prueba en un hash de hashes con elementos 4k, cada uno de unos pocos cientos de bytes, y era aproximadamente un 50% más rápido que el Marshal.dump/load

Por supuesto, no es tan completo, ya que no funcionará si tiene un hash como, por ejemplo, el valor del campo 'project_name', pero para un simple hash de 2 niveles, funciona genial/más rápido.

2

En caso de que el Marchal#dump/load par no es un trabajo, por hay una Hash 's método #deep_dup, para que pueda:

h = {'name' => 'sayuj', 
'age' => 22, 
'project' => {'project_name' => 'abc', 
       'duration' => 'prq'}} 

h1 = h.deep_dup 
+1

el método debe ser h.deep_dup en lugar de h.deep. dup – yopefonic

+0

El método 'deep_dup' convertirá una Clase en una Clase anónima, no recomendada. –

+0

@TianChen ejemplo? –

0

Otra alternativa es utilizar la gema full_dup (descripción completa: soy el autor de esa gema) que maneja matrices, hashes, estructuras, y es extensible a las clases definidas por el usuario.

de usar:

require 'full_dup' 
# Other code omitted ... 
d = h.full_dup 

También tenga en cuenta que full_dup se encarga de las relaciones de datos complejos, incluyendo aquellos con bucles o la recursión.

Cuestiones relacionadas