Ruby:将数组转换为哈希时注入问题 [英] Ruby: inject issue when turning array into hash

查看:30
本文介绍了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. 累加器的类型和块的返回类型必须相同
  2. 不传递显式累加器时,累加器的类型与元素类型相同

在这种情况下,第 1 条规则会咬你.当你做类似的事情

acc[key] = 值

在您的块中,分配评估为分配的值,而不是分配的接收者.您必须将其替换为

acc.tap { acc[key] = value }

另见为什么Ruby注入方法不能总结没有初始值的字符串长度?

<小时>

顺便说一句:您可以使用解构绑定使您的代码更具可读性:

a.inject({}) {|r, (key, value)|r[key] = 值;r }

a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
a.inject({}) {|r, val| r[val[0]] = val[1]}

When I run this, I get an index error

When I change the block to

a.inject({}) {|r, val| r[val[0]] = val[1]; r}

It then works.

How is ruby handling the first inject attempt that isn't getting what I want?
Is there a better way to do this?

解决方案

Just because Ruby is dynamically and implicitly typed doesn't mean that you don't have to think about types.

The type of Enumerable#inject without an explicit accumulator (this is usually called reduce) is something like

reduce :: [a] → (a → a → a) → a

or in a more Rubyish notation I just made up

Enumerable[A]#inject {|A, A| A } → A

You will notice that all the types are the same. The element type of the Enumerable, the two argument types of the block, the return type of the block and the return type of the overall method.

The type of Enumerable#inject with an explicit accumulator (this is usually called fold) is something like

fold :: [b] → a → (a → b → a) → a

or

Enumerable[B]#inject(A) {|A, B| A } → A

Here you see that the accumulator can have a different type than the element type of the collection.

These two rules generally get you through all Enumerable#inject-related type problems:

  1. the type of the accumulator and the return type of the block must be the same
  2. when not passing an explicit accumulator, the type of the accumulator is the same as the element type

In this case, it is Rule #1 that bites you. When you do something like

acc[key] = value

in your block, assignments evaluate to the assigned value, not the receiver of the assignment. You'll have to replace this with

acc.tap { acc[key] = value }

See also Why Ruby inject method cannot sum up string lengths without initial value?


BTW: you can use destructuring bind to make your code much more readable:

a.inject({}) {|r, (key, value)| r[key] = value; r }

这篇关于Ruby:将数组转换为哈希时注入问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆