2011-01-14 136 views
23

我正在尋找一種方式在Ruby中選擇數組中的每個第n項。例如,選擇每第二個項目將改變:如何選擇數組中的每個第n項?

["cat", "dog", "mouse", "tiger"] 

到:

["dog", "tiger"] 

是否有一個Ruby的方法,這樣做,或是否有任何其他方式做到這一點?

我嘗試使用類似:

[1,2,3,4].select {|x| x % 2 == 0} 
# results in [2,4] 

但只適用於與整數,而不是字符串數組。

回答

15

您還可以使用步驟:

n = 2 
a = ["cat", "dog", "mouse", "tiger"] 
b = (n - 1).step(a.size - 1, n).map { |i| a[i] } 
5

這個怎麼樣 -

arr = ["cat", "dog", "mouse", "tiger"] 
n = 2 
(0... arr.length).select{ |x| x%n == n-1 }.map { |y| arr[y] } 
    #=> ["dog", "tiger"] 
+0

這很好的anshul。謝謝! – sjsc 2011-01-14 08:42:41

4

如果你需要在其他地方,你可以添加一個方法Enumerable

module Enumerable 
    def select_with_index 
     index = -1 
     (block_given? && self.class == Range || self.class == Array) ? select { |x| index += 1; yield(x, index) } : self 
    end 
end 

p ["cat", "dog", "mouse", "tiger"].select_with_index { |x, i| x if i % 2 != 0 } 

注:這不是我的原代碼。當我有和你一樣的需求時,我從here得到它。

+0

這太好了。謝謝Zabba! – sjsc 2011-01-14 08:55:33

+3

在1.9中,您可以將其寫爲`to_enum.with_index.select` – 2011-01-14 09:34:53

+7

在1.9中,您可以將它寫爲`.select.with_index` – Nakilon 2011-01-14 12:18:38

48

您可以使用Enumerable#each_slice

["cat", "dog", "mouse", "tiger"].each_slice(2).map(&:last) 
# => ["dog", "tiger"] 

更新:

正如評論所說,last並不總是合適的,所以它可能替換爲first,並跳過第一個元素:

["cat", "dog", "mouse", "tiger"].drop(1).each_slice(2).map(&:first) 

不幸的是,使它不那麼優雅。

IMO,最優雅的是使用.select.with_index,其中Nakilon在他的評論中建議:

["cat", "dog", "mouse", "tiger"].select.with_index{|_,i| (i+1) % 2 == 0} 
4

另一種方式:

xs.each_with_index.map { |x, idx| x if idx % 2 != 0 }.compact 

xs.each_with_index.select { |x, idx| idx % 2 }.map(&:first) 

xs.values_at(*(1...xs.length).step(2)) 
4

你可以簡單的使用方法values_at。您可以在documentation中輕鬆找到它。

下面是一些例子:

array = ["Hello", 2, "apple", 3] 
array.values_at(0,1) # pass any number of arguments you like 
=> ["Hello", 2] 

array.values_at(0..3) # an argument can be a range 
=>["Hello", 2, "apple", 3] 

我相信這將與 「狗」 和 「老虎」

array = ["cat", "dog", "mouse", "tiger"] 
array.values_at(1,3) 

,並與另一個陣列解決您的問題

[1,2,3,4].values_at(1,3) 
=> [2, 4] 
4

我喜歡Anshul和Mu的答案,並希望通過提交每個作爲monkeypatch來改進和簡化它們到可枚舉:

module Enumerable 
    def every_nth(n) 
    (n - 1).step(self.size - 1, n).map { |i| self[i] } 
    end 
end 

Anshul的

module Enumerable 
    def every_nth(n) 
    (0... self.length).select{ |x| x%n == n-1 }.map { |y| self[y] } 
    end 
end 

然後,它是非常容易的工作。例如,考慮:

a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25] 

a.every_nth(2) 
=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24] 

a.every_nth(3) 
=> [3, 6, 9, 12, 15, 18, 21, 24] 

a.every_nth(5) 
=> [5, 10, 15, 20, 25] 
2

我建議一個非常簡單的方法:

animals.each_with_index.map { |_, i| i.odd? } 

例如

['a','b','c','d'].select.with_index{ |_,i| i.odd? } 
=> ["b", "d"]