簡體   English   中英

使用self.dup,但未通過rspec測試以不修改原始數組

[英]Using self.dup, but failing rspec test to not modify original array

我正在創建一種方法來轉置方形二維數組。 我的方法通過了所有測試,但“不修改原始數組”除外。 我僅在重復陣列上工作,所以我對測試失敗的原因感到困惑。

碼:

class Array
  def my_transpose
    orig_arr = self.dup; array = []
    orig_arr[0].length.times do
      temp_arr = []
      orig_arr.each { |arr| temp_arr << arr.shift }
      array << temp_arr
    end
    array
  end
end

RSpec:

describe Array do  

  describe "#my_transpose" do
        let(:arr) { [
          [1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]
        ] }

    let(:small_arr) { [
      [1, 2],
      [3, 4]
    ] }

    it "transposes a small matrix" do
      expect(small_arr.my_transpose).to eq([
        [1, 3],
        [2, 4]
      ])
    end

    it "transposes a larger matrix" do
      expect(arr.my_transpose).to eq([
        [1, 4, 7],
        [2, 5, 8],
        [3, 6, 9]
      ])
    end

    it "should not modify the original array" do
      small_arr.my_transpose

      expect(small_arr).to eq([
        [1, 2],
        [3, 4]
      ])
    end

    it "should not call the built-in #transpose method" do
      expect(arr).not_to receive(:transpose)

      arr.my_transpose
    end
  end
end

輸出:

  7) Array#my_transpose should not modify the original array
     Failure/Error: expect(small_arr).to eq([

       expected: [[1, 2], [3, 4]]
            got: [[], []]

       (compared using ==)
     # ./spec/00_array_extensions_spec.rb:123:in `block (3 levels) in <top (required)>'

當您在數組上調用dup時,它只會復制數組本身。 數組的內容也不會重復。 因此,例如:

a = [[1,2],[3,4]]
b = a.dup
a.object_id == b.object_id        # => false
a[0].object_id == b[0].object_id  # => true

因此,對a 本身的修改不會反映在b (反之亦然),但是對a 元素的修改會反映在b ,因為這些元素是相同的對象。

既然如此,問題就出現在這里:

orig_arr.each { |arr| temp_arr << arr.shift }

arrorig_arr的元素,但它也是 self的元素。 如果您執行了諸如從orig_arr 刪除它orig_arr ,那么您也不會從self刪除它,但是如果您對其進行更改,則無論您如何訪問它,它都將被更改,事實證明, Array#shift是一種破壞性操作。

為了使代碼按預期工作,可能需要對代碼進行的最小更改是使用each_with_index ,然后將索引使用到arr ,而不是調用arr.shift ,因此:

orig_arr.each_with_index { |arr,i| temp_arr << arr[i] }

但是,實際上,一旦執行了此操作,就根本不會執行任何破壞性的操作,並且不需要orig_arr ,就可以使用self

原始數組不被修改,但的陣列,作為dup是一個淺克隆。

xs = [[1,2],[3,4]]
ids = xs.map(&:object_id)
xs.my_transpose
ids == xs.map(&:object_id)  #=> true

由於shift是一種變異操作(對嵌套數組元素執行),因此您還需要在數組中dup元素,例如

orig_arr = dup.map(&:dup)

進行此修改后,您的測試應該可以通過。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM