ruby-on-rails - content_tag link_to rails
¿Cómo seleccionas cada elemento nth en una matriz? (8)
Estoy buscando una manera de seleccionar Ruby en cada elemento en una matriz. Por ejemplo, seleccionar cada segundo elemento transformaría:
["cat", "dog", "mouse", "tiger"]
dentro:
["dog", "tiger"]
¿Hay un método de Ruby para hacerlo, o hay alguna otra manera de hacerlo?
Intenté usar algo como:
[1,2,3,4].select {|x| x % 2 == 0}
# results in [2,4]
pero eso solo funciona para una matriz con enteros, no cadenas.
Me gustan tanto las respuestas de Anshul como las de Mu y quiero refinarlas y simplificarlas un poco enviándolas como un Monkeypatch a Enumerable:
De mu
module Enumerable
def every_nth(n)
(n - 1).step(self.size - 1, n).map { |i| self[i] }
end
end
De Anshul
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 él. 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]
Otra forma más:
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))
Puedes usar Enumerable#each_slice
:
["cat", "dog", "mouse", "tiger"].each_slice(2).map(&:last)
# => ["dog", "tiger"]
Actualizar:
Como se mencionó en el comentario, el last
no siempre es adecuado, por lo que podría ser reemplazado por el primer elemento y omitir el primer elemento:
["cat", "dog", "mouse", "tiger"].drop(1).each_slice(2).map(&:first)
Desafortunadamente, haciéndolo menos elegante.
En mi opinión, lo 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}
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"]
Si necesita eso en otros lugares, puede agregar un método a 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 de here cuando tuve la misma necesidad que tú.
Simplemente puedes usar el método values_at
. Puedes encontrarlo fácilmente en la documentation .
Aquí hay unos 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 solucionaría tu problema con "perro" y "tigre"
array = ["cat", "dog", "mouse", "tiger"]
array.values_at(1,3)
y con tu otra matriz
[1,2,3,4].values_at(1,3)
=> [2, 4]
Sugeriría una manera muy simple:
animals.select.with_index{ |_, i| i.odd? }
p.ej
[''a'',''b'',''c'',''d''].select.with_index{ |_,i| i.odd? }
# => ["b", "d"]
También puedes usar el paso:
n = 2
a = ["cat", "dog", "mouse", "tiger"]
b = (n - 1).step(a.size - 1, n).map { |i| a[i] }