2016-08-09 24 views
0

我正在创建一个方法来转置方形2维数组。我的方法通过了每个测试,除了“不修改原始数组”之外。我只是在处理数组,所以我很困惑为什么测试失败。使用self.dup,但未通过rspec测试不能修改原始数组

代码:

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)>' 
+0

@JonnyHenly因为RSpec的使用是偶然发生的问题,所以只是测试问题的一种手段。 –

+0

@AndrewMarshall哦,我明白了。 –

+0

@JonnyHenly这不是必然的*所有问题的情况下,但它在这里:) –

回答

2

当您在数组上调用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,你也不会从self中删除它,但是如果你改变它,它会改变,无论你如何访问它,事实证明,Array#shift是一个破坏性的操作。

也许你可以使你的代码的最小变化,使像您期望的是使用each_with_index,然后使用索引arr,而不是调用arr.shift它的工作,所以:

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

在但事实上,一旦你这样做,你根本没有做任何破坏性的操作,你不需要orig_arr,你可以使用self

1

原始阵列不被修改,但这些阵列它是作为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) 

通过此修改,您的测试应通过。