2010-01-11 11 views
14

Tengo una matriz bidimensional en Ruby de la que quiero producir un duplicado de trabajo. Obviamente no puedo hacer esto;¿Hay una manera simple de duplicar una matriz multidimensional en Ruby?

array=[[3,4],[5,9],[10,2],[11,3]] 
temp_array=array 

como las modificaciones que haga a temp_array también se hará a la matriz, como simplemente ha copiado el identificador de objeto. Pensé que sería capaz de evitar esto simplemente usando;

temp_array=array.dup 

pero esto no funciona como temp_array es simplemente un conjunto de identificadores de objetos que consiguen duplican así que aún así terminar la modificación de la matriz inicial (si entiendo lo que salió mal cuando hice esto). La solución que encontré fue hacer lo siguiente;

temp_array=[] 
array.each{|sub| temp_array << sub.dup} 

Esto logra lo que quiero pero parece ser una forma incómoda de resolver mi problema.

Me preocupa cómo funcionaría esto si no supiera lo que mi matriz iba a contener (por ejemplo, si era posible que algunas partes de la matriz tuvieran 3 dimensiones). Probablemente tendría que probar la clase de cada miembro de la matriz para ver si tenía que repetirla para poder duplicarla. No es una tarea imposible en absoluto, pero me parece desordenada. ¿Es simplemente una consecuencia de que Ruby carezca de soporte integrado para matrices multidimensionales o hay una función incorporada simple para hacer esto que me he perdido?

Respuesta

29

Aquí está el "Rubí-esque" manera de manejarlo:

temp_array = Marshal.load(Marshal.dump(your_array_to_be_cloned))

+3

Ese es el camino. Me gusta poner ese código en Object.deep_copy. –

+0

Genial, gracias. En realidad, esto explica todo el asunto de Marshalling para mí (aunque necesito ir y hacer más lecturas para realmente entenderlo). – brad

-7

Prueba esto:

temp_array = array.clone 
-8

Usted puede utilizar array.clone como se especifica here. Eso le dará una copia del objeto original, y no solo un puntero.

2

Como han señalado otras personas, puede usar clonar. Sin embargo, esto no funcionará, ya que es una copia superficial, por lo que las matrices secundarias (esto no es realmente una matriz multidimensional, creo) no se clonarán. Como las matrices son objetos mutables en Ruby, las matrices secundarias se cambiarán. Por ejemplo, mira esto

>> blah = [[3,5],6] 
=> [[3, 5], 6] 
>> joe = blah.clone 
=> [[3, 5], 6] 
>> joe[0] 
=> [3, 5] 
>> joe[0].push "blah" 
=> [3, 5, "blah"] 
>> blah 
=> [[3, 5, "blah"], 6] 

Así que como puedes ver, simplemente haciendo clon no funcionará. Pero lo sabías, de ahí tu pregunta.

He cocinado esto ahora. Esto funcionará hasta que descubras la forma real de Ruby de hacerlo (solo trabajo en Ruby, no soy un experto).

def dup_recursive(new_array, old_array) 
    old_array.each do |item| 
    if item.class == Array 
     new_array << dup_recursive([], item) 
    else 
     new_item = item.dup rescue new_item = item # in case it's got no dupe, like FixedNum 
     new_array << new_item 
    end 
    new_array 
    end 
end 

array=[[3,[9,12]],[5,9],[10,2],[11,3]] 
new_array = Array.new 
dup_recursive(new_array, array) 
puts array.inspect 
puts new_array.inspect 

lo sé, no estoy usando pato-escribir, pero estaría contento de ser educados en cuanto a cómo hacer esto sin pedir la clase del objeto en cuestión.

Editar: que debería haber buscado en solo rubí profundo-clon de Google, pero a veces me gusta escribir código:) ... de todos modos, la otra solución presentada - Marshal.load(Marshal.dump(array)) - también funcionará para hashes y etcétera, así que es mucho mejor.

+0

Eso es realmente un pequeño pedazo de código. Es lo que temía que iba a tener que escribir para tratar este tema, pero lo hice mucho mejor de lo que lo hubiera hecho. Es interesante la cantidad de personas que acudieron directamente a la solución de clonación; este tema obviamente no es bien entendido por muchos Rubyistas. – brad

+0

Tal vez sea cierto, Brad, pero por otro lado, tal vez tienes una mala muestra (de personas, respuestas). Podría ser la hora del día, la redacción de la pregunta o cualquier otra cosa. O podría ser que muchos Rubyistas no entiendan este tema. Desafortunadamente, Rails te protege de tener que entender cualquier cosa :) –

-1

Pruebe ejecutar array.dup en cada subarreglo dentro de la matriz.

c = [] 
    array.each do |row| 
     c << row.dup 
    end 
0

Puede utilizar DeepEnumerable 's deep_dup para esto:

>> require 'deep_enumerable' 

>> array=[[3,4],[5,9],[10,2],[11,3]] 

>> temp_array=array.deep_dup 
>> array.each{|sub| sub << "XXX"} 

>> array 
=> [[3, 4, "XXX"], [5, 9, "XXX"], [10, 2, "XXX"], [11, 3, "XXX"]] 

>> temp_array 
=> [[3, 4], [5, 9], [10, 2], [11, 3]] 
2

No es la mejor manera de hacer exacta y copia verdadera del matriz multidimensional en Ruby es Marshalling.

Aquí es el Rubí sintaxis del de clasificación:

Marshal.load(Marshal.dump(Name_Of_Your_Original_Array))

Vamos a ver cómo utilizar esta sintaxis utilizando el ejemplo anterior es decir

array=[[3,4],[5,9],[10,2],[11,3]] temp_array=array

En este ejemplo, solo crea un objeto que apunta a la misma ubicación de memoria de la matriz, no está haciendo la copia real de nuestra matriz. Aquí, si modifica el valor de su temp_array, reflejará automáticamente los cambios en la matriz original que es la variable array en nuestro ejemplo. Entonces, ¿cómo evitar que los cambios automáticos sucedan en nuestra matriz original? Podemos hacerlo por clasificación.

So! ¿cómo podemos hacer esto, en el ejemplo que tenemos que hacer una copia real de la matriz en el temp_array.

Vamos a ver, cómo hacer esto:

array=[[3,4],[5,9],[10,2],[11,3]] temp_array = Marshal.load(Marshal.dump(array))

Ahora, hemos hecho la copia real de nuestra matriz multidimensional, si modifica cualquier valor de sus temp_array entonces los cambios no refleje su original array.

Cuestiones relacionadas