Ответ 1
Здесь используется способ Ruby-esque:
temp_array = Marshal.load(Marshal.dump(your_array_to_be_cloned))
У меня есть двумерный массив в Ruby, который я хочу создать рабочий дубликат. Очевидно, я не могу этого сделать;
array=[[3,4],[5,9],[10,2],[11,3]]
temp_array=array
поскольку любые изменения, которые я делаю для temp_array, также будут переданы в массив, поскольку я просто скопировал идентификатор объекта. Я думал, что смогу обойти это, просто используя;
temp_array=array.dup
но это не работает, поскольку temp_array - это просто массив идентификаторов объектов, которые дублируются, поэтому я все же в конечном итоге модифицирую исходный массив (если я понимаю, что пошло не так, когда я это сделал). Решение, которое я нашел, состояло в следующем:
temp_array=[]
array.each{|sub| temp_array << sub.dup}
Это достигает того, чего я хочу, но, похоже, является неудобным способом решения моей проблемы.
Меня беспокоит, как это будет работать, если я не знаю, что будет содержать мой массив (например, если возможно, что некоторые части массива имеют 3-мерные размеры). Мне, возможно, придется протестировать класс каждого члена массива, чтобы увидеть, нужно ли его повторять, чтобы его дублировать. Не совсем невозможная задача, но мне кажется бесполезной. Это просто следствие того, что Ruby не имеет встроенной поддержки многомерных массивов или есть простая встроенная функция для этого, которую я пропустил?
Здесь используется способ Ruby-esque:
temp_array = Marshal.load(Marshal.dump(your_array_to_be_cloned))
Как указывали другие люди, вы можете использовать клон. Однако это не сработает, так как это мелкая копия, поэтому, например, субмассивы (на мой взгляд, это не многомерный массив) не будут клонированы. Поскольку массивы являются изменяемыми объектами в Ruby, субмассивы будут изменены. Например, проверьте это
>> 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]
Итак, как вы можете видеть, просто выполнение клона не будет работать. Но вы знали это, следовательно, ваш вопрос.
Я приготовил это сейчас. Это будет сделано до тех пор, пока вы не узнаете реальный рубиновый способ сделать это (я просто работаю в Ruby, я не эксперт).
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 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
Я знаю, я не использую утиную печать, но я был бы рад, если бы я учился, как это сделать, не спрашивая класс рассматриваемого объекта.
Изменить: Я должен был просто обыскать глубокий клон рубина в Google, но иногда мне нравится писать код:)... в любом случае, другое решение представлено - Marshal.load( Marshal.dump( array ) )
- также будет работать для хэшей и т.д., поэтому лучше.
Существует лучший способ сделать точную и реальную копию многомерного массива в Ruby Маршаллинг.
Вот синтаксис Ruby сортировки:
Marshal.load(Marshal.dump(Name_Of_Your_Original_Array))
Посмотрите, как использовать этот синтаксис, используя приведенный выше пример, т.е.
array=[[3,4],[5,9],[10,2],[11,3]]
temp_array=array
В этом примере он создает только объект, который указывает на то же расположение памяти массива, что не делает реальной копии нашего массива. Здесь, если вы измените значение своего temp_array
, оно автоматически отразит изменения в исходном массиве, который является переменной array
в нашем примере. Итак, как мы можем предотвратить автоматические изменения в нашем исходном массиве, мы можем сделать это путем сортировки.
Итак! как это сделать, в примере нам нужно сделать реальную копию массива в temp_array.
Посмотрим, как это сделать:
array=[[3,4],[5,9],[10,2],[11,3]]
temp_array = Marshal.load(Marshal.dump(array))
Теперь мы выполнили реальную копию нашего многомерного массива, если вы измените любое значение вашего temp_array
, тогда изменения не будут отражать ваш оригинальный array
.
Вы можете использовать DeepEnumerable deep_dup для этого
>> 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]]
Попробуйте запустить array.dup для каждого вспомогательного массива в массиве.
c = []
array.each do |row|
c << row.dup
end
Попробуйте следующее:
temp_array = array.clone
Вы можете использовать array.clone
как указано здесь. Это даст вам копию исходного объекта, а не только указателя.