Есть ли простой способ дублирования многомерного массива в Ruby?

У меня есть двумерный массив в 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 не имеет встроенной поддержки многомерных массивов или есть простая встроенная функция для этого, которую я пропустил?

Ответы

Ответ 1

Здесь используется способ Ruby-esque:

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

Ответ 2

Как указывали другие люди, вы можете использовать клон. Однако это не сработает, так как это мелкая копия, поэтому, например, субмассивы (на мой взгляд, это не многомерный массив) не будут клонированы. Поскольку массивы являются изменяемыми объектами в 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 ) ) - также будет работать для хэшей и т.д., поэтому лучше.

Ответ 3

Существует лучший способ сделать точную и реальную копию многомерного массива в 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.

Ответ 4

Вы можете использовать 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]]

Ответ 5

Попробуйте запустить array.dup для каждого вспомогательного массива в массиве.

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

Ответ 6

Попробуйте следующее:

temp_array = array.clone

Ответ 7

Вы можете использовать array.clone как указано здесь. Это даст вам копию исходного объекта, а не только указателя.