¿Cuál es la forma de "correcta" de iterar a través de una matriz en Ruby? -- ruby campo con arrays campo con loops camp Relacionados El problema

What is the “right” way to iterate through an array in Ruby?


352
vote

problema

Español

PHP, para todos sus defectos, es bastante bueno en este aspecto. No hay diferencia entre una matriz y un hash (tal vez soy ingenuo, pero esto parece obvio derecho a mí), y para iterar a través de cualquiera de los dos que acaba de hacer

  foreach (array/hash as $key => $value)   

En Rubí hay un montón de maneras de hacer este tipo de cosas:

  array.length.times do |i| end  array.each  array.each_index  for i in array   

hashes tiene más sentido, ya que siempre uso

  hash.each do |key, value|   

Por qué no puedo hacer esto para las matrices? Si quiero recordar sólo un método, creo que puedo usar each_index (ya que hace que tanto el índice como valor disponible), pero es molesto tener que hacer array[index] en vez de tan sólo value .


Ah, claro, que se olvidó de array.each_with_index . Sin embargo, ésta es una mierda porque va c_p = c_char_p() windll.thedll.FormatError(errcode, c_p) 0 y c_p = c_char_p() windll.thedll.FormatError(errcode, c_p) 1 va c_p = c_char_p() windll.thedll.FormatError(errcode, c_p) 2 ! ¿Esto no está loco?

Original en ingles

PHP, for all its warts, is pretty good on this count. There's no difference between an array and a hash (maybe I'm naive, but this seems obviously right to me), and to iterate through either you just do

foreach (array/hash as $key => $value) 

In Ruby there are a bunch of ways to do this sort of thing:

array.length.times do |i| end  array.each  array.each_index  for i in array 

Hashes make more sense, since I just always use

hash.each do |key, value| 

Why can't I do this for arrays? If I want to remember just one method, I guess I can use each_index (since it makes both the index and value available), but it's annoying to have to do array[index] instead of just value.


Oh right, I forgot about array.each_with_index. However, this one sucks because it goes |value, key| and hash.each goes |key, value|! Is this not insane?

</div
        
   
   

Lista de respuestas

575
 
vote
vote
La mejor respuesta
 

Esto itará a través de todos los elementos:

  array = [1, 2, 3, 4, 5, 6] array.each { |x| puts x }   

Impresiones:

  1 2 3 4 5 6   

Esto iterará a través de todos los elementos que le dan el valor y el índice:

  array = ["A", "B", "C"] array.each_with_index {|val, index| puts "#{val} => #{index}" }   

Impresiones:

  A => 0 B => 1 C => 2   

No estoy seguro de su pregunta que está buscando.

 

This will iterate through all the elements:

array = [1, 2, 3, 4, 5, 6] array.each { |x| puts x } 

Prints:

1 2 3 4 5 6 

This will iterate through all the elements giving you the value and the index:

array = ["A", "B", "C"] array.each_with_index {|val, index| puts "#{val} => #{index}" } 

Prints:

A => 0 B => 1 C => 2 

I'm not quite sure from your question which one you are looking for.

</div
 
 
   
   
91
 
vote

Creo que no hay nadie derecha . Hay muchas maneras diferentes de iterar, y cada una tiene su propio nicho.

  • each es suficiente para muchos usos, ya que a menudo no me importa los índices.
  • each_ with _index actúa como hash # cada uno: obtiene el valor y el índice.
  • each_index - Solo los índices. No uso este a menudo. Equivalente a "longitud".
  • restype0 es otra forma de iterar, útil cuando desea transformar una matriz en otra.
  • restype1111 es el iterador que desea usar cuando desea elegir un subconjunto.
  • restype2 es útil para generar sumas o productos, o recopilar un solo resultado.

Puede parecer mucho que recordar, pero no se preocupe, puede conseguirlo sin conocerlos a todos. Pero a medida que comienza a aprender y usar los diferentes métodos, su código se convertirá en más limpio y más claro, y estará en camino a Ruby Mastery.

 

I think there is no one right way. There are a lot of different ways to iterate, and each has its own niche.

  • each is sufficient for many usages, since I don't often care about the indexes.
  • each_ with _index acts like Hash#each - you get the value and the index.
  • each_index - just the indexes. I don't use this one often. Equivalent to "length.times".
  • map is another way to iterate, useful when you want to transform one array into another.
  • select is the iterator to use when you want to choose a subset.
  • inject is useful for generating sums or products, or collecting a single result.

It may seem like a lot to remember, but don't worry, you can get by without knowing all of them. But as you start to learn and use the different methods, your code will become cleaner and clearer, and you'll be on your way to Ruby mastery.

</div
 
 
 
 
60
 
vote

No estoy diciendo que Array - & gt; |value,index| Y Hash - & gt; |key,value| no está loco (vea el comentario de Horace Loeb), pero estoy diciendo que existe una forma sana de esperar este arreglo.

Cuando estoy tratando con matrices, me estoy enfocando en los elementos de la matriz (no el índice porque el índice es transitorio). El método es cada uno con índice, es decir, cada índice +, o | cada uno, índice |, o |value,index| . Esto también es consistente con el índice que se ve como un argumento opcional, por ejemplo. | valor | es equivalente a | valor, index = nil | que es consistente con | valor, índice |.

Cuando se trata de hashes, a menudo estoy más enfocado en las llaves que los valores, y generalmente estoy tratando con claves y valores en ese orden, ya sea 9988777665 o hash[key] = value < / Código>.

Si desea escribir en pato, ya sea explícitamente use un método definido como se mostró Brent Longborough, o un método implícito como se mostró Maxhawkins.

Ruby se trata de acomodar el idioma para adaptarse al programador, no sobre el programador que se adapta al idioma. Por eso hay tantas maneras. Hay tantas maneras de pensar en algo. En Ruby, eliges lo más cercano y el resto del código generalmente cae extremadamente de forma perfectamente y concisa.

En cuanto a la pregunta original, "¿Cuál es la forma de" correcta "a iterar a través de una matriz en Ruby?", Bueno, creo que la forma central (es decir, sin poder de azúcar sintáctica o un poder orientado a objetos) es hacer: < / p>

  for index in 0 ... array.size   puts "array[#{index}] = #{array[index].inspect}" end   

Pero Ruby es todo sobre poderoso azúcar sintáctico y energía orientada a objetos, pero de todos modos, aquí es el equivalente para los hashes, y las llaves se pueden ordenar o no:

  for key in hash.keys.sort   puts "hash[#{key.inspect}] = #{hash[key].inspect}" end   

Entonces, mi respuesta es "La forma de" correcta "de iterar a través de una matriz en Ruby depende de usted (es decir, el programador o el equipo de programación) y el proyecto". El mejor programador de rubíes hace que la mejor opción (de la cual la energía sintáctica y / o qué enfoque orientado a objetos). El mejor programador de rubíes continúa buscando más maneras.


Ahora, quiero hacer otra pregunta: "¿Cuál es la forma de" correcta "de iterar a través de un rango en Ruby hacia atrás?"! (Esta pregunta es cómo llegué a esta página.)

Es bueno hacer (para los delanteros):

  (1..10).each{|i| puts "i=#{i}" }   

pero no me gusta hacer (por el revés):

  |value,index|0  

Bueno, en realidad no me importa mucho hacer eso, pero cuando estoy enseñando yendo hacia atrás, quiero mostrarle a mis alumnos una simetría agradable (es decir, con una diferencia mínima, por ejemplo, solo agregar un reverso o un paso -1 , pero sin modificar nada más). Usted puede hacer (por simetría):

  |value,index|111  

y

  |value,index|2  

que no me gusta mucho, pero no puedes hacer

  |value,index|3  

, en última instancia, podría hacerlo

  |value,index|4  

Pero quiero enseñar rubí puro en lugar de enfoques orientados a objetos (todavía). Me gustaría iterar hacia atrás:

  • sin crear una matriz (considere 0..1000000000)
  • trabajando para cualquier rango (por ejemplo, cadenas, no solo enteros)
  • sin usar cualquier poder orientado a objetos adicionales (es decir, no hay modificación de clase)

Creo que esto es imposible sin definir un método |value,index|5 , lo que significa modificar la clase de rango para usarla. Si puede hacer esto, hágamelo saber, de lo contrario, la confirmación de la imposibilidad se apreciaría, aunque sería decepcionante. Tal vez Ruby 1.9 aborda esto.

(gracias por su tiempo en leer esto).

 

I'm not saying that Array -> |value,index| and Hash -> |key,value| is not insane (see Horace Loeb's comment), but I am saying that there is a sane way to expect this arrangement.

When I am dealing with arrays, I am focused on the elements in the array (not the index because the index is transitory). The method is each with index, i.e. each+index, or |each,index|, or |value,index|. This is also consistent with the index being viewed as an optional argument, e.g. |value| is equivalent to |value,index=nil| which is consistent with |value,index|.

When I am dealing with hashes, I am often more focused on the keys than the values, and I am usually dealing with keys and values in that order, either key => value or hash[key] = value.

If you want duck-typing, then either explicitly use a defined method as Brent Longborough showed, or an implicit method as maxhawkins showed.

Ruby is all about accommodating the language to suit the programmer, not about the programmer accommodating to suit the language. This is why there are so many ways. There are so many ways to think about something. In Ruby, you choose the closest and the rest of the code usually falls out extremely neatly and concisely.

As for the original question, "What is the "right" way to iterate through an array in Ruby?", well, I think the core way (i.e. without powerful syntactic sugar or object oriented power) is to do:

for index in 0 ... array.size   puts "array[#{index}] = #{array[index].inspect}" end 

But Ruby is all about powerful syntactic sugar and object oriented power, but anyway here is the equivalent for hashes, and the keys can be ordered or not:

for key in hash.keys.sort   puts "hash[#{key.inspect}] = #{hash[key].inspect}" end 

So, my answer is, "The "right" way to iterate through an array in Ruby depends on you (i.e. the programmer or the programming team) and the project.". The better Ruby programmer makes the better choice (of which syntactic power and/or which object oriented approach). The better Ruby programmer continues to look for more ways.


Now, I want to ask another question, "What is the "right" way to iterate through a Range in Ruby backwards?"! (This question is how I came to this page.)

It is nice to do (for the forwards):

(1..10).each{|i| puts "i=#{i}" } 

but I don't like to do (for the backwards):

(1..10).to_a.reverse.each{|i| puts "i=#{i}" } 

Well, I don't actually mind doing that too much, but when I am teaching going backwards, I want to show my students a nice symmetry (i.e. with minimal difference, e.g. only adding a reverse, or a step -1, but without modifying anything else). You can do (for symmetry):

(a=*1..10).each{|i| puts "i=#{i}" } 

and

(a=*1..10).reverse.each{|i| puts "i=#{i}" } 

which I don't like much, but you can't do

(*1..10).each{|i| puts "i=#{i}" } (*1..10).reverse.each{|i| puts "i=#{i}" } # (1..10).step(1){|i| puts "i=#{i}" } (1..10).step(-1){|i| puts "i=#{i}" } # (1..10).each{|i| puts "i=#{i}" } (10..1).each{|i| puts "i=#{i}" }   # I don't want this though.  It's dangerous 

You could ultimately do

class Range    def each_reverse(&block)     self.to_a.reverse.each(&block)   end  end 

but I want to teach pure Ruby rather than object oriented approaches (just yet). I would like to iterate backwards:

  • without creating an array (consider 0..1000000000)
  • working for any Range (e.g. Strings, not just Integers)
  • without using any extra object oriented power (i.e. no class modification)

I believe this is impossible without defining a pred method, which means modifying the Range class to use it. If you can do this please let me know, otherwise confirmation of impossibility would be appreciated though it would be disappointing. Perhaps Ruby 1.9 addresses this.

(Thanks for your time in reading this.)

</div
 
 
   
   
19
 
vote

Utilice cada_with_index cuando lo necesite.

  |value,index|6  
 

Use each_with_index when you need both.

ary.each_with_index { |val, idx| # ... 
</div
 
 
12
 
vote

Las otras respuestas están bien, pero quería señalar otra cosa periférica: se ordenan las matrices, mientras que los hashes no están en 1.8. (En Ruby 1.9, los hashes se ordenan mediante orden de inserción de claves). Por lo tanto, no tendría sentido antes de 1.9 a iterar sobre un hash de la misma manera / secuencia que las matrices, que siempre han tenido un ordenamiento definido. No sé cuál es la orden predeterminada para las matrices de asociación PHP (aparentemente, mi Google Fu no es lo suficientemente fuerte como para descubrirlo, pero tampoco sé cómo puede considerar las matrices regulares de PHP y las matrices asociativas PHP para ser "lo mismo" en este contexto, ya que el pedido de matrices asociativas parece indefinido.

Como tal, la forma de Ruby me parece más clara e intuitiva para mí. :)

 

The other answers are just fine, but I wanted to point out one other peripheral thing: Arrays are ordered, whereas Hashes are not in 1.8. (In Ruby 1.9, Hashes are ordered by insertion order of keys.) So it wouldn't make sense prior to 1.9 to iterate over a Hash in the same way/sequence as Arrays, which have always had a definite ordering. I don't know what the default order is for PHP associative arrays (apparently my google fu isn't strong enough to figure that out, either), but I don't know how you can consider regular PHP arrays and PHP associative arrays to be "the same" in this context, since the order for associative arrays seems undefined.

As such, the Ruby way seems more clear and intuitive to me. :)

</div
 
 
     
     
10
 
vote

Aquí están las cuatro opciones enumeradas en su pregunta, organizadas por la libertad de control. Es posible que desee usar uno diferente dependiendo de lo que necesite.

  1. Simplemente vaya a través de los valores:

      array.each   
  2. Simplemente vaya a través de los índices:

      array.each_index   
  3. Ir a través de Índices + índice variable:

      for i in array   
  4. Variable de conteo de la bucle de control + índice:

      array.length.times do | i |   
 

Here are the four options listed in your question, arranged by freedom of control. You might want to use a different one depending on what you need.

  1. Simply go through values:

    array.each 
  2. Simply go through indices:

    array.each_index 
  3. Go through indices + index variable:

    for i in array 
  4. Control loop count + index variable:

    array.length.times do | i | 
</div
 
 
9
 
vote

Tratando de hacer lo mismo consistentemente con arreglos y hashes podría ser un olor a código, pero, a riesgo de que me estén marcando como un parche de Monkey-Monkey Cody Monkey, si estás Buscando un comportamiento consistente, ¿esto hará el truco?:

  class Hash     def each_pairwise         self.each { | x, y |             yield [x, y]         }     end end  class Array     def each_pairwise         self.each_with_index { | x, y |             yield [y, x]         }     end end  ["a","b","c"].each_pairwise { |x,y|     puts "#{x} => #{y}" }  {"a" => "Aardvark","b" => "Bogle","c" => "Catastrophe"}.each_pairwise { |x,y|     puts "#{x} => #{y}" }   
 

Trying to do the same thing consistently with arrays and hashes might just be a code smell, but, at the risk of my being branded as a codorous half-monkey-patcher, if you're looking for consistent behaviour, would this do the trick?:

class Hash     def each_pairwise         self.each { | x, y |             yield [x, y]         }     end end  class Array     def each_pairwise         self.each_with_index { | x, y |             yield [y, x]         }     end end  ["a","b","c"].each_pairwise { |x,y|     puts "#{x} => #{y}" }  {"a" => "Aardvark","b" => "Bogle","c" => "Catastrophe"}.each_pairwise { |x,y|     puts "#{x} => #{y}" } 
</div
 
 
5
 
vote

He estado tratando de construir un menú (en Camping y Markaby ) usando un hash.

Cada elemento tiene 2 elementos: una etiqueta de menú y una url , por lo que un hash parecía correcto, pero la URL '/' para 'Inicio' siempre apareció en el último ( Como esperas por un hash), así que los elementos del menú aparecieron en el orden incorrecto.

Uso de una matriz con each_slice hace el trabajo:

  ['Home', '/', 'Page two', 'two', 'Test', 'test'].each_slice(2) do|label,link|    li {a label, :href => link} end   

Agregar valores adicionales para cada elemento del menú (por ejemplo, como un nombre de CSS ID ) Simplemente significa aumentar el valor de la rebanada. Entonces, como un hash, pero con grupos que consisten en cualquier número de artículos. Perfecto.

¡Así que esto es solo para decir gracias por insinuarse inadvertidamente en una solución!

obvio, pero vale la pena afirmar: sugiero verificar si la longitud de la matriz es divisible por el valor de la rebanada.

 

I'd been trying to build a menu (in Camping and Markaby) using a hash.

Each item has 2 elements: a menu label and a URL, so a hash seemed right, but the '/' URL for 'Home' always appeared last (as you'd expect for a hash), so menu items appeared in the wrong order.

Using an array with each_slice does the job:

['Home', '/', 'Page two', 'two', 'Test', 'test'].each_slice(2) do|label,link|    li {a label, :href => link} end 

Adding extra values for each menu item (e.g. like a CSS ID name) just means increasing the slice value. So, like a hash but with groups consisting of any number of items. Perfect.

So this is just to say thanks for inadvertently hinting at a solution!

Obvious, but worth stating: I suggest checking if the length of the array is divisible by the slice value.

</div
 
 
4
 
vote

Si usa el enumerable mixin (como lo hace los rieles) Puedes hacer algo similar al fragmento PHP enumerado. Simplemente use el método de cada_slice y aplana el hash.

  require 'enumerator'   ['a',1,'b',2].to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" }  # is equivalent to...  {'a'=>1,'b'=>2}.to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" }   

Menos parches de mono requeridos.

Sin embargo, esto causa problemas cuando tiene una matriz recursiva o un hash con valores de matriz. En Ruby 1.9 Este problema se resuelve con un parámetro al método aplanado que especifica cuán profundos para recurtar.

  # Ruby 1.8 [1,2,[1,2,3]].flatten => [1,2,1,2,3]  # Ruby 1.9 [1,2,[1,2,3]].flatten(0) => [1,2,[1,2,3]]   

En cuanto a la pregunta de si se trata de un olor a código, no estoy seguro. Por lo general, cuando tengo que agacharme hacia atrás para iterar sobre algo que retrocede y me doy cuenta de que estoy atacando al problema mal.

 

If you use the enumerable mixin (as Rails does) you can do something similar to the php snippet listed. Just use the each_slice method and flatten the hash.

require 'enumerator'   ['a',1,'b',2].to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" }  # is equivalent to...  {'a'=>1,'b'=>2}.to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" } 

Less monkey-patching required.

However, this does cause problems when you have a recursive array or a hash with array values. In ruby 1.9 this problem is solved with a parameter to the flatten method that specifies how deep to recurse.

# Ruby 1.8 [1,2,[1,2,3]].flatten => [1,2,1,2,3]  # Ruby 1.9 [1,2,[1,2,3]].flatten(0) => [1,2,[1,2,3]] 

As for the question of whether this is a code smell, I'm not sure. Usually when I have to bend over backwards to iterate over something I step back and realize I'm attacking the problem wrong.

</div
 
 
3
 
vote

En Ruby 2.1, cada método_index se elimina. En su lugar, puede usar cada_index

Ejemplo:

  a = [ "a", "b", "c" ] a.each_index {|x| print x, " -- " }   

Produce:

  array.each_index 0  
 

In Ruby 2.1, each_with_index method is removed. Instead you can use each_index

Example:

a = [ "a", "b", "c" ] a.each_index {|x| print x, " -- " } 

produces:

0 -- 1 -- 2 -- 
</div
 
 
 
 
2
 
vote

La forma correcta es la que se siente más cómoda y que hace lo que quiere que haga. En la programación, rara vez hay una manera de hacer las cosas, más a menudo hay múltiples formas de elegir.

Si se siente cómodo con ciertas cosas de las cosas, hágalo, a menos que no funcione, entonces es hora de encontrar mejor camino.

 

The right way is the one you feel most comfortable with and which does what you want it to do. In programming there is rarely one 'correct' way to do things, more often there are multiple ways to choose.

If you are comfortable with certain way of doings things, do just it, unless it doesn't work - then it is time to find better way.

</div
 
 
0
 
vote

El uso del mismo método para la iteración a través de ambas matrices y los hashes tiene sentido, por ejemplo, para procesar estructuras de hash y matriz anidadas a menudo resultantes de analizadores, desde la lectura de archivos JSON, etc.

Una forma inteligente que aún no se ha mencionado es cómo se hace en la facetas de rubí biblioteca de extensiones estándar de la biblioteca. Desde aquí :

  array.each_index 111  

Ya hay array.each_index 2 , un alias de array.each_index 3 . Entonces, después de este parche, también tenemos 99887776614 y puede usarlo indistintamente para iterar a través de los hashes y las matrices. Esto corrige la locura observada de OP que array.each_index 5 tiene los argumentos de bloques invertidos en comparación con array.each_index 6 . Ejemplo de uso:

  array.each_index 7  
 

Using the same method for iterating through both arrays and hashes makes sense, for example to process nested hash-and-array structures often resulting from parsers, from reading JSON files etc..

One clever way that has not yet been mentioned is how it's done in the Ruby Facets library of standard library extensions. From here:

class Array    # Iterate over index and value. The intention of this   # method is to provide polymorphism with Hash.   #   def each_pair #:yield:     each_with_index {|e, i| yield(i,e) }   end  end 

There is already Hash#each_pair, an alias of Hash#each. So after this patch, we also have Array#each_pair and can use it interchangeably to iterate through both Hashes and Arrays. This fixes the OP's observed insanity that Array#each_with_index has the block arguments reversed compared to Hash#each. Example usage:

my_array = ['Hello', 'World', '!'] my_array.each_pair { |key, value| pp "#{key}, #{value}" }  # result:  "0, Hello" "1, World" "2, !"  my_hash = { '0' => 'Hello', '1' => 'World', '2' => '!' } my_hash.each_pair { |key, value| pp "#{key}, #{value}" }  # result:  "0, Hello" "1, World" "2, !" 
</div
 
 

Relacionados problema

-6  Rendimiento de bucles anidados [cerrado]  ( Nested loops performance ) 
Es difícil decir qué se está preguntando aquí. Esta pregunta es ambigua, vaga, incompleta, demasiado amplia, o retórica y n...

1  Bucle, contando y el método setinterval  ( Looping counting and the setinterval method ) 
1) ¿Esta técnica de construcción funcionaría? ¿O necesitaría tener esto.start ()? 2) ¿El reinicio del índice en cualquier punto? var imageRotate = new tR...

3  Jekyll / líquido para el bucle siendo misterioso  ( Jekyll liquid for loop being mysterious ) 
Estoy tratando de usar el bucle POR en Jekyll para hacer datos de muestra. Puedo hacer referencia a los objetos de descuento o lo que sea que se llame directa...

0  Lista a través del archivo usando un bucle while  ( List through file using a while loop ) 
No puedo hacer que esto funcione correctamente, necesito que el programa enumere a través de los registros dentro del archivo, si $ registros [$ fila] [2] es ...

2  Python / Selenium Stale Element Referencia en el bucle  ( Python selenium stale element reference in for loop ) 
Estoy teniendo problemas en bucle a través de una lista de identificación de la empresa y usándolos en una barra de búsqueda. Mi código funciona bien cuando e...

352  ¿Cuál es la forma de "correcta" de iterar a través de una matriz en Ruby?  ( What is the right way to iterate through an array in ruby ) 
PHP, para todos sus defectos, es bastante bueno en este aspecto. No hay diferencia entre una matriz y un hash (tal vez soy ingenuo, pero esto parece obvio der...

3  C ++ Array ... necesita ayuda para comprender el código  ( C c array need help understanding code ) 
¿Puedes por favor explicar este código? Me parece un poco confuso para mí. ¿Es "A" una doble matriz? Pensaría que es solo un número entero, pero luego en la d...

0  PHP Posible fugas de memoria  ( Php possible memory leak ) 
Tengo un script que se bucea a través de una base de datos para que las imágenes se conviertan con GD & AMP; Imagick. i Desactive o reemplace todas las vari...

0  Documento no está listo para insertar después del método usando un bucle con jQuery  ( Document not ready for insert after method using a loop with jquery ) 
¿Hay alguna forma de usar un bucle para insertar elementos divecuarios separados detrás de uno a otro? ahora mismo uso un bucle para hacer precisamente eso,...

44  ¿Cómo me conecto a una base de datos y un bucle sobre un conjunto de registros en C #?  ( How do i connect to a database and loop over a recordset in c ) 
¿Cuál es la forma más sencilla de conectar y consultar una base de datos para un conjunto de registros en C #? ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos