Ruby:将数组转换为哈希时注入问题

MxL*_*evs 12 ruby

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. 累加器的类型和块的返回类型必须相同
  2. 当没有传递显式累加器时,累加器的类型与元素类型相同

在这种情况下,规则#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)


x1a*_*1a4 9

有一种更简单的方法 -

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设置为传递给它的参数,在本例中为{}.