[英]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 }
arr
是orig_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.