a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']] a.inject({}) {|r, val| r[val[0]] = val[1]}
当我运行它时,我得到一个索引错误
当我将块更改为
a.inject({}) {|r, val| r[val[0]] = val[1]; r}
它然后工作.
ruby如何处理第一次注射尝试没有得到我想要的?
有一个更好的方法吗?
Jör*_*tag 13
仅仅因为Ruby是动态和隐式类型的,并不意味着你不必考虑类型.
Enumerable#inject
没有显式累加器的类型(通常称为reduce
)类似于
reduce :: [a] ? (a ? a ? a) ? a
Run Code Online (Sandbox Code Playgroud)
或者用一种更简洁的符号来构建
Enumerable[A]#inject {|A, A| A } ? A
Run Code Online (Sandbox Code Playgroud)
您会注意到所有类型都是相同的.块的元素类型,Enumerable
块的两个参数类型,块的返回类型以及整个方法的返回类型.
Enumerable#inject
带有显式累加器的类型(通常称为fold
)类似于
fold :: [b] ? a ? (a ? b ? a) ? a
Run Code Online (Sandbox Code Playgroud)
要么
Enumerable[B]#inject(A) {|A, B| A } ? A
Run Code Online (Sandbox Code Playgroud)
在这里,您可以看到累加器可以具有与集合的元素类型不同的类型.
这两条规则通常会Enumerable#inject
引导您解决所有相关的类型问题:
在这种情况下,规则#1咬你.当你做类似的事情
acc[key] = value
Run Code Online (Sandbox Code Playgroud)
在您的块中,分配评估为分配的值,而不是分配的接收者.你必须用它替换它
acc.tap { acc[key] = value }
Run Code Online (Sandbox Code Playgroud)
另请参见为什么Ruby注入方法无法在没有初始值的情况下总结字符串长度?
顺便说一句:您可以使用destructuring bind来使您的代码更具可读性:
a.inject({}) {|r, (key, value)| r[key] = value; r }
Run Code Online (Sandbox Code Playgroud)
有一种更简单的方法 -
a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
b = Hash[a] # {1=>"a", 2=>"b", 3=>"c", 4=>"d"}
Run Code Online (Sandbox Code Playgroud)
第一种方法不起作用的原因是因为inject使用块的结果作为r
下一次迭代.对于第一次迭代,r
设置为传递给它的参数,在本例中为{}
.