2016-03-01 74 views
0

我有这样的代码红宝石注入创建阵列

notebooks.inject([]) do |res, nb| 
    res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name) 
end 

第一nb具有相匹配的条件和res看起来像这样

["xxx1234"] 

第二nb不符合条件,然后删除/清除res

nil 

从我的理解,第一个值应该保留在数组中。

我也将此分配给一个变量,并希望它是一个班轮。

回答

4

inject工作从你如何想象有点不同。它只是返回循环的最后一个返回值,因为它循环遍历每个项目。一个简单的方法来解决这个是:

notebooks.inject([]) do |res, nb| 
    res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name) 
    res # Returns the res array 
end 

这就是说,你应该使用select您的使用情况下,你似乎只是过滤下来,其设置的笔记本电脑你想..这就是:

notebooks.select{|nb| Recipe::NOTEBOOKS.include?(nb.name)}.map(&:guid) 

一般来说,我用inject当我需要在一组项目上运行数学。例如

[1,2,3,4].inject(0) {|res, x| x * 2 + res} 
0

累加器必须在每个循环迭代返回:

notebooks.inject([]) do |res, nb| 
    Recipe::NOTEBOOKS.include?(nb.name) ? res << nb.guid : res 
end 

事实上,在以后每次循环迭代,传递给res块参数累加器是正是从以前的迭代返回。不执行

在你的榜样,在第二次迭代if回报false

res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name) 

线在所有。也就是说,在第二次迭代之后,累加器会获得一个全新的值,这显然是nil

1

如果你打开两个循环,但更清洁,还是一个班轮:

notebooks.select { |nb| Recipe::NOTEBOOKS.include?(nb.name) }.map(&:guid) 
+1

+1正是我在想什么。这也有助于可读性,因为您将问题分为两个不同的步骤。尽管如此,我至少将它分成两行。 – Kelvin