Duplicación de un array de cadenas de Ruby
Pregunta
arr = ["red","green","yellow"]
arr2 = arr.clone
arr2[0].replace("blue")
puts arr.inspect
puts arr2.inspect
produce:
["blue", "green", "yellow"]
["blue", "green", "yellow"]
¿Hay alguna forma de hacer una copia profunda de una matriz de cadenas, con excepción de usar Mariscal como yo entiendo que es un truco.
lo que podía hacer:
arr2 = []
arr.each do |e|
arr2 << e.clone
end
pero no parece muy elegante, o eficiente.
Gracias
Solución
Su segunda solución se puede acortar a arr2 = arr.map do |e| e.dup end
(a menos que realmente necesita el comportamiento de clone
, se recomienda el uso dup
en su lugar).
Aparte de que sus dos soluciones son básicamente las soluciones estándar para realizar una copia profunda (aunque la segunda versión es sólo un nivel profundo (es decir, si la utiliza en una serie de matrices de cadenas, todavía puede mutar las cuerdas )). En realidad no hay una manera más agradable.
Edit: Aquí está un método recursivo deep_dup que trabaja con matrices arbitrariamente anidados:
class Array
def deep_dup
map {|x| x.deep_dup}
end
end
class Object
def deep_dup
dup
end
end
class Numeric
# We need this because number.dup throws an exception
# We also need the same definition for Symbol, TrueClass and FalseClass
def deep_dup
self
end
end
También puede ser que desee para definir deep_dup para otros recipientes (como Hash), de lo contrario tendrá todavía obtener una copia superficial para aquellos.
Otros consejos
Recomiendo su idea inicial, pero escrito un poco más concisa:
arr = ["red","green","yellow"]
arr2 = arr.inject([]) { |a,element| a << element.dup }
Estoy en una situación similar y muy preocupados por la velocidad. La forma más rápida para mí era hacer uso de map{&:clone}
Así que trate esto:
pry(main)> a = (10000..1000000).to_a.shuffle.map(&:to_s)
pry(main)> Benchmark.ms { b = a.deep_dup }
=> 660.7760030310601
pry(main)> Benchmark.ms { b = a.join("--!--").split("--!--") }
=> 605.0828141160309
pry(main)> Benchmark.ms { b = a.map(&:clone) }
=> 450.8283680770546
Se puede hacer una copia en profundidad de la matriz a
por código siguiente:
Marshal.load(Marshal.dump(a))
Parece tan simple .. Sólo tiene que ejecutar el siguiente código:
a = [1,2,3]
b = [].replace(a)
b[1] = 5
puts a
puts b
Ejecutar el código anterior y se dará cuenta de la diferencia. Saludos!
Se puede utilizar este truco:
arr1 = %w{ red green blue }
arr2 = arr1.join("--!--").split("--!--")
Pero es sólo por diversión:)
arr2[0].replace("lol")
p arr1
#=> ["red", "green", "blue"]
p arr2
#=> ["lol", "green", "blue"]
Y funcionará sólo para matrices de nivel 1