2015-02-06 106 views
0

Ruby程序我有紅寶石字符串比較代碼中我得到一些奇怪的輸出用於字符串比較

def matchval_not_pos(str1, str2) 
    a1, a2 = str1.chars, str2.chars 
    return 0 if a1 == a2 
    [a1.size, a2.size].min.times do |i| 
    if a1[i] == a2[i] 
     a1.delete_at(i) 
     a2.delete_at(i) 
    end 
    end 
    a1.reduce(0) do |t,c| 
    i = a2.index(c) 
    if i 
     inc = 1 
     a2.delete_at(i) 
    else 
     inc = 0 
    end 
    t + inc 
    end 
end 

我上撬控制檯獲得輸出

=> :matchval_not_pos 
[12] pry(main)> matchval_not_pos("abc","abc") 
=> 0 
[13] pry(main)> matchval_not_pos("abcd","abc") 
=> 1 
[14] pry(main)> matchval_not_pos("abcde","abc") 
=> 1 
[15] pry(main)> matchval_not_pos("abcdef","abc") 
=> 1 
[16] pry(main)> matchval_not_pos("abcdefgh","abc") 
=> 1 
[17] pry(main)> matchval_not_pos("abcdefgh","abcdefghi") 
=> 4 
[18] pry(main)> matchval_not_pos("abcdefgh","abcdefghijklmn") 
=> 4 
[19] pry(main)> matchval_not_pos("abcdefghijklmn","abcdefghijklmn") 
=> 0 
[20] pry(main)> matchval_not_pos("abcdefghijklmnop","abcdefghijklmn") 
=> 7 
[21] pry(main)> matchval_not_pos("abcdefghijklmnop","abcdefghijklmnop") 
=> 0 
[22] pry(main)> matchval_not_pos("abcdefghijklmnop","abcdefghijklmnopqw") 
=> 8 
[23] pry(main)> matchval_not_pos("abcdefghijklmnop","abcdefghijklmnop") 
=> 0 

我不能排序這就是爲什麼我得到這個輸出。有人能幫助我嗎?

+3

你期待什麼輸出_were_? – 2015-02-06 12:06:27

+0

如果matchval_not_pos(「abc」,「abc」) => 0 &pry(main)> matchval_not_pos(「abcde」,「abc」)=> 2如果直到3個字符串匹配,在str1中增加charector字符串like(「abcdefg」,「abcd」)它給了我錯誤的輸出 – user4537116 2015-02-06 12:09:53

+1

你可能做的一件事是將'matchval_not_pos'分解成更小的方法併爲每種方法編寫單元測試。實際上可能會幫助您更快地進行調試,此外您還可以測試所有邊界案例。 – aceofbassgreg 2015-02-06 15:23:02

回答

0

我沒有經歷過,整個閱讀剪斷你貼,但我注意到像你期望它這部分將不工作:

[a1.size, a2.size].min.times do |i| 
    if a1[i] == a2[i] 
    a1.delete_at(i) 
    a2.delete_at(i) 
    end 
end 

這裏的錯誤是,你正在修改陣列(與#delete_at)同時循環播放。

即,如果您a1.delete_at(1),您更改索引1後的所有字符的索引,並更改數組的長度。

基本上,事情不同步。

在這種情況下,一種解決方案是做a1[i] = nil而不是a1.delete_at(i),然後在循環的外面做a1.compact!

0

爲了說明standfarback指出的問題,讓我們來看看爲什麼在循環中從數組中刪除項目不是你的方法。

比方說,我們有以下值的兩個數組:

x = ["a", "b", "c", "d"] 
y = ["a", "b", "c", "d", "e", "f", "g"] 

現在,讓我們把他們通過你的循環:

[x.size, y.size].min.times do |i| 
    if x[i] == y[i] 
     x.delete_at(i) 
     y.delete_at(i) 
    end 
end 

這意味着,我們將循環4次。第一次通過循環,i將是0。所以,x[0]"a"y[0]"a"。這意味着我們在兩個陣列上都有.delete_at(0)。這意味着,通過第一循環結束後,我們的陣列將是這樣的:

x = ["b", "c", "d"] 
y = ["b", "c", "d", "e", "f", "g"] 

看看發生了什麼?我們刪除了數組中的第一個元素,現在一切都在向下滑動以填充空白。所以,現在我們第二次穿過循環,現在i1。我們將看看x[1]y[1]這是比較"c""c"。我們完全跳過"b"

這意味着你只檢查每一個其他元素。

有很多可能的解決方案來比較陣列,但如果您愛上使用.delete_at的概念,您是否考慮過使用方法.downto?它會和.times有相同的影響,但它會從一個數字開始並減少。所以:

([x.size, y.size].min - 1).downto(0) do |i| 
    if x[i] == y[i] 
     x.delete_at(i) 
     y.delete_at(i) 
    end 
end 

現在,當我們第一次通過循環時,我們將首先檢查最後一個元素。所以,如果我們.delete_at(3),它不會在下一次迭代中拋棄我們。

同樣,這不是最好的解決方案,但它是一個可能的解決方案。我同意aceofbassgreg,你應該把它分解成更小的方法,併爲變量提供更有意義的名稱。

我希望這可以幫助您瞭解在循環過程中如何從陣列中移除元素可以提供奇怪的結果。