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 如何处理第一次没有得到我想要的注入尝试?
有一个更好的方法吗?
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 如何处理第一次没有得到我想要的注入尝试?
有一个更好的方法吗?
仅仅因为 Ruby 是动态和隐式类型的,并不意味着您不必考虑类型。
没有显式累加器的类型Enumerable#inject
(通常称为reduce
)类似于
reduce :: [a] → (a → a → a) → a
或者我刚刚编造的更红宝石的符号
Enumerable[A]#inject {|A, A| A } → A
您会注意到所有类型都是相同的。的元素类型,Enumerable
块的两个参数类型,块的返回类型和整体方法的返回类型。
Enumerable#inject
带有显式累加器(通常称为)的类型fold
类似于
fold :: [b] → a → (a → b → a) → a
或者
Enumerable[B]#inject(A) {|A, B| A } → A
在这里,您看到累加器可以具有与集合的元素类型不同的类型。
这两条规则通常可以帮助您解决所有Enumerable#inject
相关的类型问题:
在这种情况下,规则#1 会咬你一口。当你做类似的事情时
acc[key] = value
在您的块中,分配评估为分配的值,而不是分配的接收者。您必须将其替换为
acc.tap { acc[key] = value }
另请参阅为什么 Ruby 注入方法无法总结没有初始值的字符串长度?
顺便说一句:您可以使用解构绑定使您的代码更具可读性:
a.inject({}) {|r, (key, value)| r[key] = value; r }
有一个更简单的方法 -
a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
b = Hash[a] # {1=>"a", 2=>"b", 3=>"c", 4=>"d"}
第一种方法不起作用的原因是,inject 将块的结果用作r
下一次迭代中的结果。对于第一次迭代,r
设置为您传递给它的参数,在本例中为{}
.
第一个块将分配的结果返回到 中inject
,第二个块返回哈希,所以它确实有效。
很多人认为这种inject
反模式的用法。each_with_object
改为考虑。
a.inject({}) { |r, val| r.merge({ val[0] => val[1] }) }