我是Ruby的新手,我正在尝试编写一个方法,将一组单词分组为anagram组。这是代码:
def combine_anagrams(words)
dict = words.inject(Hash.new(0)) do |list,ws|
key = sort_word(ws)
if !list.has_key?(key)
list[key] = []
end
list[key].push(ws)
list #What is this
end
return dict.values
end
我的问题是list
的陈述是什么。如果我拿出它,列表就变成了数组而不是哈希。
答案 0 :(得分:1)
每个方法/块/等。在Ruby中返回一些东西,除非有一个早期的return
语句,无论方法/块/ etc中的最后一个语句是什么。是,是归还的。
在您的情况下,让list
成为传递给inject
的块中的最后一行,可确保块返回list
。当你删除它时,会返回list[key].push(ws)
的返回值,这显然不是你想要的。
请注意,此行为还会使return
关键字成为最后一个将被执行的语句,否则是不必要的(这包括方法结束时的return
)。虽然有些人更愿意明确表示他们打算退回某些东西,即使在不需要的时候也会使用它们。
在不相关的注释中:您的if !list.has_key?(key)
可以重写unless list.has_key?(key)
。
答案 1 :(得分:1)
inject
的工作原理如下:
final = enumerable.inject(initial_value) do |current_value, iteration|
# calculations, etc. here
value # next iteration, current_value will be whatever the block returns
end
因此,在您的情况下,initial_value
为Hash.new(0)
,或者为0
的空哈希值作为不存在的密钥的默认值,而不是nil
。这将传递到inject
中第一个元素的enumerable
块。
在注入块内部,检查是否已将key
作为哈希上的键存在。如果没有,则将其设置为空数组。在任何一种情况下,取当前迭代words
(ws
)并将其推送到数组上。
最后,该块返回当前版本的list
;它将在下次循环处理来自current_value
的元素时变为inject
(enumerable
块的第一个参数)。
作为一个更简单的示例,请查看此示例:
numbers = [1, 2, 3, 4]
sum = inject(0) do |total, number| # first time, total will be 0
total + number # set total next time to be whatever total is now plus the current number
end
答案 2 :(得分:0)
查看http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject
在inject方法中,如果你传入两个参数(在你的case列表和ws中),第一个 - list - 就是所谓的累加器值。每个迭代步骤中注入块返回的值被分配给列表变量。因此,使用您所评论为“#What is this”的唯一单词“list”的行用于将块中列表的值分配给“list”累加器变量。
答案 3 :(得分:0)
语句“list”是整个块的返回值。行:“list [key] = []”的返回值为“list”,因此它不需要另一行将if条件的返回值设置为'list',而是list [key]的返回值.push(ws)是列表[key]。我们希望最终得到列表的更新值,因此我们需要每次从块中返回该值,以便进一步处理更新列表的行为,而不是别的。
作为背景,每个ruby行也有一个返回值,所以如果它是一个块或函数的最后一行,它会自动成为整个块或函数的返回值。
要进一步理解这一点,请在irb中尝试这样的代码:
a = [1,2,3,4,5]
b = a.inject(0) {|sum, val| puts sum; puts val; sum + val}
内部块包括三个状态;最后一个语句将sum + val的值返回到块中,该值以sum的形式存储,以便在下一次迭代中使用。
另外,尝试这样的代码:
h = {:a => []}
b = h[:a].push 6
查看b评估的内容;在你的代码中,你需要'b'作为累积的哈希值,而不是存储在h [:a]
中的数组