2009-12-10 44 views
3

我該如何實現?我認爲我的解決方案非常骯髒,我希望能夠做得更好。我認爲在Ruby中有這樣一個簡單的方法,但我不記得了。我想在Rails中使用它,所以如果Rails提供類似的東西,那也可以。用法應該是這樣的:Ruby/Rails:從索引可被x整除的數組中獲取元素

fruits = ['banana', 'strawberry', 'kiwi', 'orange', 'grapefruit', 'lemon', 'melon'] 

# odd_fruits should contain all elements with odd indices (index % 2 == 0) 
odd_fruits = array_mod(fruits, :mod => 2, :offset => 0) 

# even_fruits should contain all elements with even indices (index % 2 == 1) 
even_fruits = array_mod(fruits, :mod => 2, :offset => 1) 

puts odd_fruits 
    banana 
    kiwi 
    grapefruit 
    melon 

puts even_fruits 
    strawberry 
    orange 
    lemon 

*******編輯*******

對於那些我們希望能夠知道,那就是我終於做到:

在Rails項目,我創建了一個新的文件config/initializers/columnize.rb它看起來像這樣:

class Array 
    def columnize args = { :columns => 1, :offset => 0 } 
    column = [] 
    self.each_index do |i| 
     column << self[i] if i % args[:columns] == args[:offset] 
    end 
    column 
    end 
end 

的Rails會自動加載這些文件的Rails已經加載之後。我也使用了爲方法提供參數的方式,因爲我認爲這是爲了更好的可讀代碼的目的,而且我是一個可讀性很好的代碼 - 戀物癖:)我擴展了核心類「Array」,現在我可以做這樣的事情,在我的項目中每個陣列以下:

>> arr = [1,2,3,4,5,6,7,8] 
=> [1, 2, 3, 4, 5, 6, 7, 8] 

>> arr.columnize :columns => 2, :offset => 0 
=> [1, 3, 5, 7] 
>> arr.columnize :columns => 2, :offset => 1 
=> [2, 4, 6, 8] 

>> arr.columnize :columns => 3, :offset => 0 
=> [1, 4, 7] 
>> arr.columnize :columns => 3, :offset => 1 
=> [2, 5, 8] 
>> arr.columnize :columns => 3, :offset => 2 
=> [3, 6] 

我現在就用它在我的意見,以顯示不同的列從數據庫條目。我喜歡它的是,我不必調用任何緊湊的方法或東西,因爲在將零對象傳遞給視圖時,rails會抱怨。現在它只是工作。我也想過讓JS做的一切,對我來說,但我比較喜歡這種方式,與960網格系統(http://960.gs

回答

5
fruits = ["a","b","c","d"] 
even = [] 
x = 2 
fruits.each_index{|index| 
    even << fruits[index] if index % x == 0 
} 
odds = fruits - even 
p fruits 
p even 
p odds 



["a", "b", "c", "d"] 
["a", "c"] 
["b", "d"] 
+0

這正是我正在尋找:)謝謝隊友! – 2009-12-12 12:03:02

+0

'odds = fruits - even'這是我喜歡紅寶石的東西 – 2011-11-16 14:48:06

3
def array_mod(arr, mod, offset = 0) 
    arr.shift(offset) 
    out_arr = [] 

    arr.each_with_index do |val, idx| 
    out_arr << val if idx % mod == 0 
    end 

    out_arr 
end 

用法工作:

>> fruits = ['banana', 'strawberry', 'kiwi', 'orange', 'grapefruit', 'lemon', 'melon'] 

>> odd_fruits = array_mod(fruits, 2) 
=> ["banana", "kiwi", "grapefruit", "melon"] 

>> even_fruits = array_mod(fruits, 2, 1) 
=> ["strawberry", "orange", "lemon"] 

>> even_odder_fruits = array_mod(fruits, 3, 2) 
=> ["kiwi", "lemon"] 
+0

我試圖找到一個更實用的方法來做到這一點(例如數組#選擇),但由於大多數Ruby的函數數組方法不公開索引。 – 2009-12-10 17:02:47

3

什麼你要的是:

even_fruits = fruits.select_with_index { |v,i| i % 2 == 0) } 
odd_fruits = fruits - even_fruits 

可惜Enumerable#select_with_index不存在作爲標準,但有幾個人擁有電子用這樣的方法擴展Enumerable

http://snippets.dzone.com/posts/show/3746 http://webget.com/gems/webget_ruby_ramp/doc/Enumerable.html#M000058

+0

+1當然!,如果你用cat'fruit [i]'獲取它,那麼你不需要這個值,然後使用'each_index'做 – OscarRyz 2009-12-10 17:16:04

+0

但是使用你指出的那個,你的塊必須是'i%2 == 0',而不僅僅是'i%2',這將永遠是真的...... – 2009-12-11 02:39:20

+0

愚蠢的我,當然零評價爲真正!歡呼glenn! ;) – 2009-12-11 03:22:00

1

Rails提供一個的ActiveSupport擴展陣列,可提供一個 「in_groups_of」 的方法。這就是我通常用於這樣的事情。它可以讓你做到這一點:

拉甚至水果(記得要壓縮在最後的決絕尼爾斯):

fruits = ['banana', 'strawberry', 'kiwi', 'orange', 'grapefruit', 'lemon', 'melon'] 
fruits.in_groups_of(2).collect{|g| g[1]}.compact 
=> ["strawberry", "orange", "lemon"] 

拉怪的水果:

fruits.in_groups_of(2).collect{|g| g[0]}.compact 
=> ["banana", "kiwi", "grapefruit", "melon"] 

到讓每一個水果第三,你可以使用:

fruits.in_groups_of(3).collect{|g| g[0]}.compact 
=> ["banana", "orange", "melon"] 
3

我能想到的最簡單的方法是這樣的:

fruits = ["a","b","c","d"] 
evens = fruits.select {|x| fruits.index(x) % 2 == 0} 
odds = fruits - evens 

如果數組可以爲您查找索引,則不需要混淆select_with_index。我想這種方法的缺點是,如果'fruits'中有多個條目具有相同的值(index方法僅返回第一個匹配條目的索引)。

+0

現在我想到了,上面提到的缺點並不是真正的問題,因爲數組的'-'運算符與多個相同的元素共享一個類似的問題(這意味着使用'index'不會增加任何新問題)。 – bta 2009-12-10 18:38:38

+0

由於Array#index是線性時間操作,因此對於大型數據集可能會非常慢。 – ScottJ 2009-12-10 19:20:58

2

解決方案只用核心能力:

(0...((fruits.size+1-offset)/mod)).map {|i| fruits[i*mod+offset]} 
+0

哦,我喜歡這個。 – 2009-12-10 19:49:59

+0

額外的大括號:) – 2009-12-11 03:25:39

+0

哎呀。修正了,謝謝。 – 2009-12-11 16:46:21

0

功能性的方式

#fruits = [...] 
even = [] 
odd = [] 

fruits.inject(true){|_is_even, _el| even << _el if _is_even; !_is_even} 
fruits.inject(false){|_is_odd, _el| odd << _el if _is_odd; !_is_odd } 
0

下面是使用#enum_for一個解決方案,它允許您指定「到位」 #each的使用方法:

require 'enumerator' 
mod = 2 
[1, 2, 3, 4].enum_for(:each_with_index).select do |item, index| 
    index % mod == 0 
end.map { |item, index| item } 
# => [1, 2] 
相關問題