仅当在array.each的块内使用print语句时才会出现Ruby错误 [英] Ruby bug appears only when using print statements inside a block for array.each

查看:137
本文介绍了仅当在array.each的块内使用print语句时才会出现Ruby错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在 irb 中调用下面的函数 anagrams ,那么我会得到一个非空的散列容器。但是,如果您注释掉 printNo Key \ n行,则返回的散列容器现在为空。实际上,对于列表中的所有元素,似乎都会执行 elsif 分支中的代码。无论我是疯了还是有一个讨厌的bug:

','土豆','racs','四','疤痕','面霜','尖叫'])
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]

print 返回 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆