【问题标题】:Is there a simple way to duplicate a multi-dimensional array in Ruby?有没有一种简单的方法可以在 Ruby 中复制多维数组?
【发布时间】:2011-01-03 14:23:08
【问题描述】:

我在 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 arrays multidimensional-array


    【解决方案1】:

    这是处理它的“Ruby-esque”方式:

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

    【讨论】:

    • 就是这样。我喜欢将代码粘贴在 Object.deep_copy 中。
    • 太好了,谢谢。这实际上也向我解释了整个编组的事情(尽管我需要去阅读更多内容才能真正理解它)。
    【解决方案2】:

    在 Ruby 中制作精确真实副本多维数组的最佳方法是编组

    这是编组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 来做到这一点。

    所以!我们如何做到这一点,在示例中,我们需要将 array 的真实副本复制到 temp_array .

    让我们看看,如何做到这一点:

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

    现在,我们已经完成了我们的多维数组的真实副本,如果您修改temp_array 的任何值,那么这些更改将不会反映您原来的array

    【讨论】:

      【解决方案3】:

      正如其他人指出的那样,您可以使用克隆。然而,这不起作用,因为它是一个浅拷贝,所以子数组(我认为这不是一个真正的多维数组)不会被克隆。由于数组是 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 中搜索深度克隆 ruby​​,但有时我喜欢编写代码 :)... 无论如何,提出了另一个解决方案 -- Marshal.load( Marshal.dump( array ) ) --也适用于哈希等,所以它更好。

      【讨论】:

      • 这实际上是一段不错的小代码。这就是我担心我将不得不写来处理这个问题,但做得比我做的要好得多。有趣的是,有多少人直接使用了克隆解决方案——这个问题显然很多 Ruby 爱好者都不太了解。
      • 也许是真的,布拉德,但另一方面,也许你得到了一个糟糕的样本(人,答案)。可能是一天中的时间、问题的措辞或其他任何内容。或者可能是许多 Ruby 爱好者不理解这个问题。不幸的是,Rails 让你不必了解太多东西 :)
      【解决方案4】:

      您可以为此使用DeepEnumerabledeep_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】:

            您可以按照指定的here 使用array.clone。这将为您提供原始对象的副本,而不仅仅是指针。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-08-13
              • 2021-01-09
              • 2014-01-03
              • 2011-01-27
              • 1970-01-01
              • 1970-01-01
              • 2021-10-30
              • 2019-10-16
              相关资源
              最近更新 更多