Есть ли простой способ дублировать многомерный массив в Ruby? - PullRequest
17 голосов
/ 11 января 2010

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

Ответы [ 7 ]

33 голосов
/ 11 января 2010

Вот способ обработки Ruby-esque :

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

4 голосов
/ 23 июля 2016

Существует лучший способ сделать точную и реальную копию многомерного массива в Ruby - Marshalling .

Вот синтаксис Ruby сортировка :

Marshal.load(Marshal.dump(<em>Name_Of_Your_Original_Array</em>))

Давайте посмотрим, как использовать этот синтаксис, используя приведенный выше пример т.е.

array=[[3,4],[5,9],[10,2],[11,3]] temp_array=array

В этом примере он только создает объект, который указывает на то же место в памяти массива, но не делает настоящую копию нашего массива. Здесь, если вы измените значение вашего temp_array, оно будет автоматически отражать изменения в исходном массиве, который в нашем примере является переменной array. Итак, как мы можем предотвратить автоматические изменения в нашем исходном массиве, мы можем сделать это с помощью marshalling .

Так! как мы это делаем, в примере нам нужно сделать реальную копию массива в temp_array .

Посмотрим, как это сделать:

array=[[3,4],[5,9],[10,2],[11,3]] temp_array = Marshal.load(Marshal.dump(<em>array</em>))

Теперь мы сделали реальную копию нашего многомерного массива , если вы измените какое-либо значение вашего temp_array, тогда изменения не будут отражать ваш исходный array.

4 голосов
/ 11 января 2010

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

0 голосов
/ 25 марта 2016

Вы можете использовать для этого 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]]
0 голосов
/ 24 марта 2016

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

    c = []
    array.each do |row|
      c << row.dup
    end
0 голосов
/ 11 января 2010

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

0 голосов
/ 11 января 2010

Попробуйте это:

temp_array = array.clone
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...