如果我在irb中调用下面的函数anagrams
,我会得到一个非空的哈希容器。但是如果你注释掉print "No Key\n"
行,那么返回的哈希容器现在是空的。事实上,对于列表中的所有元素,elsif
分支中的代码似乎都在执行。要么我疯了,要么这里有一个讨厌的错误:
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
我安装了以下版本的ruby和irb:
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
irb 0.9.6(09/06/30)
你的问题是你使用elsif
,你的意思是else
。这个:
elsif
print "No Key\n"
aHash[aKey] = [el]
是误导性的格式,它实际上解释更像这样:
elsif(print "No Key\n")
aHash[aKey] = [el]
但print
返回nil
所以逻辑是这样的:
elsif(nil)
aHash[aKey] = [el]
和nil
在布尔上下文中是假的,所以aHash[aKey] = [el]
永远不会发生。如果你删除print
然后你最终得到这个:
elsif(aHash[aKey] = [el])
并且分配发生;在布尔上下文中也是如此(因为数组是),但在这种情况下,真实性是无关紧要的。
你想在这里使用else
:
if 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
aHash[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', '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
您还可以使用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