6

我正在学习 Ruby,遇到了注入。我正处于理解它的风口浪尖,但是当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用注入来将 (1..10) 范围的总和相加,我不太关心。这是一个随意的例子。

在实际程序中我会用它做什么?我正在学习,所以我可以继续使用 Rails,但我不必有一个以 Web 为中心的示例。我只需要一些有目的的东西,我可以把头绕起来。

谢谢大家。

4

5 回答 5

7

inject有时可以通过它的“其他”名称更好地理解reduce。它是一个对 an 进行操作Enumerable(迭代一次)并返回单个值的函数。

有许多有趣的方法可以使用它,尤其是与其他Enumerable方法链接时,例如map. 很多时候,它可以是一种更简洁、更有表现力的做事方式,即使有另一种方式来做。

像这样的例子一开始可能看起来没什么用:

range.inject {|sum, x| sum += x}

然而,变量range不必是一个简单的显式范围。它可以是(例如)从数据库返回的值列表。如果您运行一个返回购物车中价格列表的数据库查询,您可以.inject将它们全部相加并得到总和。

在简单的情况下,您可以在 SQL 查询本身中执行此操作。在更困难的情况下,例如某些物品添加了税,而有些则没有,类似的东西inject可能更有用:

cart_total = prices.inject {|sum, x| sum += price_with_tax(x)}

Enumerable当 中的对象是需要比简单数值需要更详细处理的复杂类时,或者当 Enumerable 包含需要在处理之前转换为通用类型的不同类型的对象时,这种事情也特别有用。由于inject需要一个块,因此您可以将此处的功能设置为您需要的复杂程度。

于 2012-08-20T23:46:33.920 回答
6

以下是几个inject()实际应用的示例:

[1, 2, 3, 4].inject(0) {|memo, num| memo += num; memo} # sums all elements in array

该示例遍历 [1, 2, 3, 4] 数组的每个元素,并将这些元素添加到 memo 变量(memo 通常用作块变量名称)。此示例在每次迭代后显式返回 memo,但返回也可以是隐式的。

[1, 2, 3, 4].inject(0) {|memo, num| memo += num} # also works

inject() 在概念上类似于以下显式代码:

result = 0
[1, 2, 3, 4].each {|num| result += num}
result # result is now 10

inject() 对于创建数组和散列也很有用。以下是如何使用 inject() 转换[['dogs', 4], ['cats', 3], ['dogs', 7]]{'dogs' => 11, 'cats' => 3}.

[['dogs', 4], ['cats', 3], ['dogs', 7]].inject({'dogs' => 0, 'cats' => 0}) do |memo, (animal, num)|
  memo[animal] = num
  memo
end

这是一个更通用和优雅的解决方案:

[['dogs', 4], ['cats', 3], ['dogs', 7]].inject(Hash.new(0)) do |memo, (animal, num)|
  memo[animal] = num
  memo
end

同样,inject()在概念上类似于以下代码:

result = Hash.new(0)
[['dogs', 4], ['cats', 3], ['dogs', 7]].each do |animal, num|
  result[animal] = num
end
result # now equals {'dogs' => 11, 'cats' => 3}
于 2013-12-19T18:44:08.707 回答
0

假设您在 eBay 上有一些商品的销售价格列表,而不是一个范围,并且您想知道平均价格。您可以通过注入 + 然后除以长度来做到这一点。

于 2012-08-20T23:42:15.963 回答
0

ActiveRecord 范围是一个典型案例。如果我们调用scoped一个模型,我们会得到一个对象,我们可以在该对象上链接额外的作用域。这让我们可以使用注入来建立一个搜索范围,比如说,一个参数哈希:

search_params = params.slice("first_name","last_name","city","zip").
  reject {|k,v| v.blank?}

search_scope = search_params.inject(User.scoped) do |memo, (k,v)|
  case k
  when "first_name"
    memo.first_name(v)
  when "last_name"
    memo.last_name(v)
  when "city"
    memo.city(v)
  when "zip"
    memo.zip(v)
  else
    memo
  end

(注意:如果没有提供参数,这会带回整个表格,这可能不是您想要的。)

于 2012-08-21T02:03:39.507 回答
0

我最喜欢的对 inject 或它的同义词 reduce 的解释是:

reduce 接收一个数组并将其减少为单个值。它通过遍历一个列表、沿途保持和转换一个运行总计来做到这一点。

我在 http://railspikes.com/2008/8/11/understanding-map-and-reduce的一篇精彩文章中找到了它

于 2013-05-06T19:18:56.930 回答