Дублирование массива строк Ruby
arr = ["red","green","yellow"]
arr2 = arr.clone
arr2[0].replace("blue")
puts arr.inspect
puts arr2.inspect
дает:
["blue", "green", "yellow"]
["blue", "green", "yellow"]
Есть ли способ сделать глубокую копию массива строк, кроме использования маршала, поскольку я понимаю, что это взлом.
Я мог бы сделать:
arr2 = []
arr.each do |e|
arr2 << e.clone
end
но он не кажется очень элегантным или эффективным.
Спасибо
Ответы
Ответ 1
Второе решение можно сократить до arr2 = arr.map do |e| e.dup end
(если вам действительно не нужно поведение clone
, рекомендуется вместо этого использовать dup
).
Кроме того, ваши два решения в основном являются стандартными решениями для выполнения глубокой копии (хотя вторая версия является только одноуровневой (т.е. если вы используете ее в массиве массивов строк, вы все равно можете мутировать строки )). На самом деле нет лучшего способа.
Изменить: здесь рекурсивный метод deep_dup, который работает с произвольно вложенными массивами:
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
Вы также можете определить deep_dup для других контейнеров (например, Hash), иначе вы все равно получите для них мелкую копию.
Ответ 2
Я рекомендую вашу первоначальную идею, но написано немного более кратко:
arr = ["red","green","yellow"]
arr2 = arr.inject([]) { |a,element| a << element.dup }
Ответ 3
Я в подобной ситуации и очень обеспокоен скоростью. Самый быстрый способ для меня состоял в использовании map{&:clone}
Итак, попробуйте следующее:
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
Ответ 4
Вы можете сделать глубокую копию массива a
следующим кодом:
Marshal.load(Marshal.dump(a))
Ответ 5
Это выглядит так просто. Просто запустите приведенный ниже код:
a = [1,2,3]
b = [].replace(a)
b[1] = 5
puts a
puts b
Запустите код выше, и вы заметите разницу. Приветствия!
Ответ 6
Вы можете использовать этот хак:
arr1 = %w{ red green blue }
arr2 = arr1.join("--!--").split("--!--")
Но это просто для удовольствия:)
arr2[0].replace("lol")
p arr1
#=> ["red", "green", "blue"]
p arr2
#=> ["lol", "green", "blue"]
И он будет работать только для 1 уровня массивов