2011-01-14 22 views
23

Estoy buscando una manera en Ruby para seleccionar cada enésimo elemento en una matriz. Por ejemplo, la selección de cada segundo elemento transformaría:¿Cómo se selecciona cada enésimo elemento en una matriz?

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

en:

["dog", "tiger"] 

¿Hay un método de Ruby para hacerlo, o hay alguna otra manera de hacerlo?

He intentado utilizar algo como:

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

pero que sólo funciona para una matriz con números enteros, no cadenas.

Respuesta

15

También es posible usar paso:

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

Esto es perfecto. Muy limpio. Muchas gracias mu :) – sjsc

+1

Gracias, tenga en cuenta que he solucionado un problema que 'n = 3' mostraría. –

+1

El 'paso' no tenía sentido inicialmente ya que no he usado ese formulario antes. Es equivalente a '(n-1 ... a.size) .step (n) .map {| i | a [i]} ' – Matt

5

¿Qué tal esto -

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

Eso funciona genial anshul. ¡Gracias! – sjsc

4

Si necesita que en otros lugares, se puede añadir un método para 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 } 

Nota: Este no es mi código original. Lo obtuve del here cuando tuve la misma necesidad que tú.

+0

Esto es genial. Gracias Zabba! – sjsc

+3

En 1.9 puede escribir esto como 'to_enum.with_index.select' –

+7

En 1.9 puede escribir esto como' .select.with_index' – Nakilon

48

Puede utilizar Enumerable#each_slice:

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

Actualización:

Como se menciona en el comentario, last no siempre es adecuado, por lo que podría ser reemplazado por first, y omitir el primer elemento:

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

Lamentablemente, por lo que es menos elegante.

OMI, el más elegante es usar .select.with_index, que Nakilon sugirió en su comentario:

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

Oh mierda. Si la matriz tiene una cantidad impar de elementos, también devolverá la última. No importa, déjalo aquí como una idea ... –

+0

Muchas gracias por el puntero Mladen y el recurso para "each_slice" :) – sjsc

4

Sin embargo, otra manera:

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

Usted puede simplemente utilizar values_at método. Puede encontrarlo fácilmente en documentation.

Éstos son algunos ejemplos:

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] 

Creo que esto sería arreglar el problema con el "perro" y "tigre"

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

y con su otra matriz

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

Me gustan las respuestas de Anshul y Mu y quiero refinarlas y simplificarlas un poco enviando cada una como un monopatch a Enumerable:

de Mu

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

de

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

entonces es muy fácil trabajar con Anshul. Por ejemplo, considere:

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

me gustaría sugerir una manera muy simple:

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

por ejemplo,

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