2016-03-01 95 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