ruby - 为什么我在 ruby 中收到此错误:find_word_lengths 中的块':未定义方法 `[]=' for 3:Integer (NoMethodError)
问题描述
以下代码返回此错误:
find_word_lengths 中的块:未定义的方法 `[]=' for 3:Integer (NoMethodError)
animals = ['cat', 'horse', 'rabbit', 'deer']
def find_word_lengths(word_list)
word_list.reduce(Hash.new()) do |result, animal|
result[animal] = animal.length
end
end
puts find_word_lengths(animals)
解决方案
块的返回值是下一次迭代的累加器值。这就是折叠的工作原理。
Ruby 中的赋值计算在右侧。因此,在 的第一次迭代中reduce
,块的计算结果为3
(的长度'cat'
)。这意味着在 , is 的第二次迭代中,reduce
您实际上是在运行result
3
3['horse'] = 5
# which is equivalent to
3.[]=('horse', 5)
这就是为什么您收到错误消息,即Integer
3
不响应消息的原因[]=
。
因此,您需要确保您的块始终返回您希望在下一次迭代中用于累加器的值。像这样的东西:
word_list.reduce(Hash.new()) do |result, animal|
result.tap {|result| result[animal] = animal.length }
end
这将是显而易见的解决方案,尽管有些作弊。
word_list.reduce(Hash.new()) do |result, animal|
result.merge(animal => animal.length)
end
会更加地道。
但是,当您想要折叠成可变对象时,使用Enumerable#each_with_object
而不是Enumerable#reduce
. each_with_object
忽略块的结果,并且每次都简单地传递相同的对象。请注意,有点令人困惑的是,块参数的顺序each_with_object
与reduce
.
word_list.each_with_object(Hash.new()) do |animal, result|
result[animal] = animal.length
end
但我想最惯用的解决方案是这样的:
word_list.map {|word| [word, word.length] }.to_h
顺便说一句,在 Ruby 中,如果您不传递任何参数,则省略参数列表的括号是惯用的,因此Hash.new()
应该Hash.new
改为。比惯用语更重要的是保持一致——令人困惑的是,你省略了 的括号animal.length
,但没有Hash.new
更惯用的是,您将使用Hash
文字符号而不是Hash::new
方法,即您应该使用{}
而不是Hash.new
.
推荐阅读
- sql - 使用 SSIS 将数据加载到 SQL Server 中的多个表
- python - gRPC channel.close() 需要 10 秒
- maven - 如何在 Intellij Idea 中找出未使用的依赖项 Maven
- authorization - 如何将 AWS ECS 与 Okta 集成
- sql-server - 如何在 SQL Server 中执行“进程/函数”
- angular - Ng Zorro Ant Design 响应式表单多个错误提示
- html - 如何在 HTML 框架中显示来自 WCF 服务的 MemoryStream
- laravel - 使用上传 laravel-Excel 的用户详细信息导入 csv 数据
- javascript - 如何使用 ajax 发布复杂的 url 请求
- python - 如果我打开两个 GUI 运行 python 项目,每个的速度会比单独运行它们慢吗?