2010-04-05 3 views
10
arr = ["red","green","yellow"] 

arr2 = arr.clone 
arr2[0].replace("blue") 

puts arr.inspect 
puts arr2.inspect 

производит:Дублирование массив Рубин строк

["blue", "green", "yellow"] 
["blue", "green", "yellow"] 

Есть в любом случае сделать глубокую копию массива строк, за исключением использования Marshal, как я понимаю, что это хак.

я мог бы сделать:

arr2 = [] 
arr.each do |e| 
    arr2 << e.clone 
end 

но это, кажется, не очень элегантно, или эффективным.

Благодаря

+0

вы можете сделать более короткий встроенный блок: arr.each {| e | arr2 << e.dup} – fl00r

ответ

10

Ваше второе решение может быть сокращен до arr2 = arr.map do |e| e.dup end (если вы на самом деле не нужно поведение clone, рекомендуется использовать вместо dup).

Помимо этого, ваши два решения в основном являются стандартными решениями для выполнения глубокой копии (хотя вторая версия является только одноуровневой (т. Е. Если вы используете ее в массиве массивов строк, вы все равно можете мутировать строки)). На самом деле нет лучшего способа.

Edit: Вот рекурсивный 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), в противном случае вы все равно получите неполную копию для те.

+0

Спасибо за ваш ответ sepp2k, поэтому, если у вас есть вложенный массив, единственный способ - использовать маршал? – dangerousdave

+0

@Jon: Нет, вы также можете определить рекурсивный метод deep_dup (см. Мое редактирование), но использование маршала обычно проще. – sepp2k

+0

Не можете ли вы не исправить число и т. Д.определяя deep_dup в Object для этого ?: reply_to? (: dup)? dup: self –

1

Вы можете использовать этот хак:

arr1 = %w{ red green blue } 
arr2 = arr1.join("--!--").split("--!--") 

Но это просто для удовольствия :)

arr2[0].replace("lol") 
p arr1 
#=> ["red", "green", "blue"] 
p arr2 
#=> ["lol", "green", "blue"] 

И это будет работать только для 1 массивов уровня

+1

Он также будет работать, только если массив содержит только строки, и ни одна из строк не содержит «-! -» в качестве подстроки. – sepp2k

+0

sepp2k, yeap, это просто взломать только для одной цели :), как tetra pack – fl00r

5

Я рекомендую вашу первоначальную идею , но написано несколько более кратко:

arr = ["red","green","yellow"] 
arr2 = arr.inject([]) { |a,element| a << element.dup } 
+1

Существует проблема с DUP, если в вашем массиве есть FixNums, например integer, - не может дублировать Fixnum http://stackoverflow.com/questions/1964143/why -dont-numbers-support-dup http://stackoverflow.com/questions/19165957/ruby-cant-dup-fixnum – stack1

5

Я в подобной ситуации и очень обеспокоен скоростью. Самый быстрый способ для меня, чтобы сделать использование 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 
2

Вы можете сделать глубокую копию массива a на следующий код:

Marshal.load(Marshal.dump(a)) 
+0

Разве вы не читали запрос? Он не хочет использовать маршала ... –

2

Это выглядит так просто .. Просто запустите приведенный ниже код:

a = [1,2,3] 
b = [].replace(a) 

b[1] = 5 

puts a 
puts b 

Пропустите выше код, и вы не укажете Разница. Приветствия!

 Смежные вопросы

  • Нет связанных вопросов^_^