我在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
我在Pry Console上获得输出
=> :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
我无法理清为什么我得到这个输出。有人可以帮帮我。
答案 0 :(得分: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
)。
IE中。如果您a1.delete_at(1)
,则更改索引1之后的所有字符的索引,并更改数组的长度。
基本上,事情变得不同步了。
在这种情况下,一个解决方案是执行a1[i] = nil
而不是a1.delete_at(i)
,然后在循环之外执行a1.compact!
。
答案 1 :(得分: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"]
看看发生了什么?我们删除了数组中的第一个元素,现在所有内容都向下移动以填充空白。所以,现在我们第二次浏览循环,现在i
是1
。我们将会查看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你应该把它分解成更小的方法,并为变量提供更有意义的名称。
我希望这可以帮助您了解在循环期间从数组中删除元素如何提供奇怪的结果。