有人可以用Ruby来解释一个真实的,简单的语言用法吗?

时间:2012-08-20 23:39:31

标签: ruby inject

我正在学习Ruby,并且遇到了注入。我正处于理解它的尖端,但当我是那种需要真实世界的例子来学习某些东西的人。我遇到的最常见的例子是人们使用注入来累加(1..10)范围的总和,我可能不在乎。这是一个随意的例子。

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

谢谢大家。

5 个答案:

答案 0 :(得分:7)

inject有时可以通过其“其他”名称reduce更好地理解。它是一个在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占用了一个块,因此您可以根据需要使其功能变得复杂。

答案 1 :(得分:5)

This short video(1分钟)是我为新手遇到的inject()的最佳解释。

This blog post有一些inject()示例。

这里有几个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}

答案 2 :(得分:0)

想象一下,你有一个eBay上某些商品的销售价格清单而不是范围,你想知道平均价格。您可以通过注入+然后除以长度来实现。

答案 3 :(得分:0)

ActiveRecord范围是典型案例。如果我们在模型上调用scoped,我们就会得到一个可以链接其他范围的对象。这让我们可以使用inject来构建一个搜索范围,例如,params hash:

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

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

答案 4 :(得分:0)

我最喜欢的注射解释或它的同义词reduce是:

reduce接受数组并将其减少为单个值。它通过迭代列表,保持并转换运行总计来实现这一点。

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