仅当在array.each的块内使用print语句时才会出现Ruby错误 [英] Ruby bug appears only when using print statements inside a block for array.each
问题描述
如果我在 irb 中调用下面的函数 anagrams
,那么我会得到一个非空的散列容器。但是,如果您注释掉 printNo Key \ n
行,则返回的散列容器现在为空。实际上,对于列表中的所有元素,似乎都会执行 elsif
分支中的代码。无论我是疯了还是有一个讨厌的bug:
aHash = Hash.new()
list.each {| el |
aKey = el.downcase.chars.sort.to_a.hash
如果aHash.key?(aKey)
#printHas Key \\\
aHash [aKey] << el
elsif
#printNo Key\\\
aHash [aKey] = [el]
结束
}
返回aHash
end
我有以下版本的 ruby 和 已安装:
ruby 1.9.2p290(2011-07-09修订版本32553)[x86_64- linux]
irb 0.9.6(09/06/30)
你的问题在于你使用 elsif
,你的意思是 else
。这:
elsif
printNo Key\\\
aHash [aKey] = [el ]
是误导性格式,它实际上更像这样解释:
elsif(printNo Key\\\
)
aHash [aKey] = [el]
但 nil
逻辑是这样的:
elsif(nil)
aHash [aKey] = [el]
和 nil
在布尔上下文中为false,因此 aHash [aKey] = [el]
永远不会发生。如果你删除了 print
,那么你最终会得到这个结果:
elsif (aHash [aKey] = [el])
该分配在布尔上下文中也是如此(因为数组是),但在这种情况下真实性无关紧要。
要使用 else here:
如果aHash.key?(aKey)
aHash [aKey]< ;< el
else
aHash [aKey] = [el]
end
<更好的办法是使用一个带有数组的Hash(通过一个块)作为默认值:
aHash = Hash .new {| h,k | h [k] = []}
然后你不需要 if
完全可以做到这一点:
list.each do | el |
aKey = el.downcase.chars.sort.to_a.hash
Hash [aKey]<< el
end
你可以使用任何东西作为Ruby Hash中的一个键,所以你不要甚至不需要 .to_a.hash
,你可以简单地使用Array本身作为关键;此外, sort
会给你一个数组,所以你甚至不需要 to_a
:
list.each {| el | aHash [el.downcase.chars.sort]<< el}
有人可能会抱怨 return
在你的方法的末尾,所以我会这样做:你不需要在你的方法结尾处的 return
,只需说 aHash
它将是方法的返回值:
def anagrams(list = ['cars', '','土豆','racs','四','疤痕','面霜','尖叫'])
Hash = Hash.new {| h,k | h [k] = []}
list.each {| el | aHash [el.downcase.chars.sort]<<你可以使用 each_with_object
将它压缩得更多: def anagrams(list = ['cars','for','potatoes','racs ','four','scar','creams','scream'])
list.each_with_object(Hash.new {| h,k | h [k] = []})do | el,h |
h [el.downcase.chars.sort]<< el
end
end
但我可能会这样做减少噪音:
def anagrams(list = ['cars','for','potatoes','racs ','four','scar','creams','scream'])
h = Hash.new {| h,k | h [k] = []}
list.each_with_object(h){| el,h | h [el.downcase.chars.sort]<< el}
end
If I call the function anagrams
below in irb, I get a non-empty hash container as expected. But if you comment out the print "No Key\n"
line, the returned hash container is now empty. In fact for all elements in list the code in the elsif
branch seems to execute. Either I'm going nuts or there is a nasty bug here:
def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
aHash = Hash.new()
list.each { |el|
aKey = el.downcase.chars.sort.to_a.hash
if aHash.key?(aKey)
# print "Has Key\n"
aHash[aKey] << el
elsif
# print "No Key\n"
aHash[aKey] = [el]
end
}
return aHash
end
I have the following versions of ruby and irb installed:
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
irb 0.9.6(09/06/30)
解决方案 Your problem is that you're using an elsif
where you mean else
. This:
elsif
print "No Key\n"
aHash[aKey] = [el]
is misleading formatting, it is actually interpreted more like this:
elsif(print "No Key\n")
aHash[aKey] = [el]
but print
returns nil
so the logic is like this:
elsif(nil)
aHash[aKey] = [el]
and nil
is false in a boolean context so aHash[aKey] = [el]
never occurs. If you remove the print
then you end up with this:
elsif(aHash[aKey] = [el])
and the assignment occurs; the assignment is also true in a boolean context (because an Array is) but the truthiness is irrelevant in this case.
You want to use else
here:
if aHash.key?(aKey)
aHash[aKey] << el
else
aHash[aKey] = [el]
end
Even better would be to use a Hash with an Array (via a block) as its default value:
aHash = Hash.new { |h, k| h[k] = [ ] }
and then you don't need the if
at all, you can just do this:
list.each do |el|
aKey = el.downcase.chars.sort.to_a.hash
aHash[aKey] << el
end
And you can use anything as a key in a Ruby Hash so you don't even need to .to_a.hash
, you can simply use the Array itself as the key; furthermore, sort
will give you an array so you don't even need the to_a
:
list.each { |el| aHash[el.downcase.chars.sort] << el }
Someone will probably complain about the return
at the end of your method so I'll do it: you don't need the return
at the end of your method, just say aHash
and it will be the method's return value:
def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
aHash = Hash.new { |h, k| h[k] = [ ] }
list.each { |el| aHash[el.downcase.chars.sort] << el }
aHash
end
You could also use each_with_object
to compress it even more:
def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
list.each_with_object(Hash.new { |h, k| h[k] = [ ] }) do |el, h|
h[el.downcase.chars.sort] << el
end
end
but I'd probably do it like this to cut down on the noise:
def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
h = Hash.new { |h, k| h[k] = [ ] }
list.each_with_object(h) { |el, h| h[el.downcase.chars.sort] << el }
end
这篇关于仅当在array.each的块内使用print语句时才会出现Ruby错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!