Necesita una explicación simple del método de inyección

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

Estoy viendo este código pero mi cerebro no está registrando cómo el número 10 puede convertirse en el resultado. ¿Alguien le importaría explicar lo que está sucediendo aquí?

Puede pensar en el primer argumento de bloque como un acumulador: el resultado de cada ejecución del bloque se almacena en el acumulador y luego pasa a la siguiente ejecución del bloque. En el caso del código que se muestra arriba, está incumpliendo el acumulador, resultado, a 0. Cada ejecución del bloque agrega el número dado al total actual y luego almacena el resultado en el acumulador. La próxima llamada al bloque tiene este nuevo valor, lo agrega, lo almacena de nuevo y lo repite.

Al final del proceso, inyectar devuelve el acumulador, que en este caso es la sum de todos los valores de la matriz, o 10.

Aquí hay otro ejemplo simple para crear un hash a partir de una matriz de objetos, marcados por su representación de cadena:

 [1,"a",Object.new,:hi].inject({}) do |hash, item| hash[item.to_s] = item hash end 

En este caso, estamos configurando nuestro acumulador por defecto en un hash vacío, y luego lo llenamos cada vez que se ejecuta el bloque. Tenga en cuenta que debemos devolver el hash como la última línea del bloque, porque el resultado del bloque se almacenará nuevamente en el acumulador.

inject toma un valor para comenzar (el 0 en tu ejemplo) y un bloque, y ejecuta ese bloque una vez para cada elemento de la lista.

  1. En la primera iteración, transfiere el valor que proporcionó como valor inicial y el primer elemento de la lista, y guarda el valor que devolvió su bloque (en este caso, result + element ).
  2. A continuación, ejecuta nuevamente el bloque, pasando el resultado de la primera iteración como primer argumento, y el segundo elemento de la lista como segundo argumento, guardando nuevamente el resultado.
  3. Continúa de esta manera hasta que haya consumido todos los elementos de la lista.

La forma más fácil de explicar esto puede ser mostrar cómo funciona cada paso, para su ejemplo; este es un conjunto imaginario de pasos que muestran cómo se pudo evaluar este resultado:

 [1, 2, 3, 4].inject(0) { |result, element| result + element } [2, 3, 4].inject(0 + 1) { |result, element| result + element } [3, 4].inject((0 + 1) + 2) { |result, element| result + element } [4].inject(((0 + 1) + 2) + 3) { |result, element| result + element } [].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element } (((0 + 1) + 2) + 3) + 4 10 

La syntax para el método de inyección es la siguiente:

inject (value_initial) { |result_memo, object| block }

Vamos a resolver el ejemplo anterior, es decir,

[1, 2, 3, 4].inject(0) { |result, element| result + element }

que da el 10 como salida.

Entonces, antes de comenzar vamos a ver cuáles son los valores almacenados en cada variable:

resultado = 0 El cero vino de inyectar (valor) que es 0

element = 1 Es el primer elemento de la matriz.

¡¡¡Bueno!!! Entonces, comencemos a entender el ejemplo anterior

Paso: 1 [ 1 , 2, 3, 4].inject( 0 ) { | 0 , 1 | 0 + 1 } [ 1 , 2, 3, 4].inject( 0 ) { | 0 , 1 | 0 + 1 }

Paso: 2 [1, 2 , 3, 4].inject(0) { | 1 , 2 | 1 + 2 } [1, 2 , 3, 4].inject(0) { | 1 , 2 | 1 + 2 }

Paso: 3 [1, 2, 3 , 4].inject(0) { | 3 , 3 | 3 + 3 } [1, 2, 3 , 4].inject(0) { | 3 , 3 | 3 + 3 }

Paso: 4 [1, 2, 3, 4 ].inject(0) { | 6 , 4 | 6 + 4 } [1, 2, 3, 4 ].inject(0) { | 6 , 4 | 6 + 4 }

Paso: 5 [1, 2, 3, 4].inject(0) { | 10 , Now no elements left in the array, so it'll return 10 from this step | } [1, 2, 3, 4].inject(0) { | 10 , Now no elements left in the array, so it'll return 10 from this step | }

Aquí los valores negrita-cursiva son elementos que se obtienen de la matriz y los valores simplemente negrita son los valores resultantes.

Espero que entiendas el funcionamiento del método #inject de #ruby .

El código itera sobre los cuatro elementos dentro de la matriz y agrega el resultado anterior al elemento actual:

  • 1 + 2 = 3
  • 3 + 3 = 6
  • 6 + 4 = 10

Lo que dijeron, pero tenga en cuenta también que no siempre es necesario proporcionar un “valor inicial”:

 [1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

es lo mismo que

 [1, 2, 3, 4].inject { |result, element| result + element } # => 10 

Pruébalo, voy a esperar.

Cuando no se pasa ningún argumento para inyectar, los primeros dos elementos pasan a la primera iteración. En el ejemplo anterior, el resultado es 1 y el elemento es 2 la primera vez, por lo que se realiza una llamada menos al bloque.

El número que coloca dentro de su () de inyección representa un punto de partida, podría ser 0 o 1000. Dentro de las tuberías tiene dos marcadores de posición | x, y |. x = el número que tengas dentro de .inject (‘x’), y el segundo representa cada iteración de tu objeto.

[1, 2, 3, 4].inject(5) { |result, element| result + element } # => 15

1 + 5 = 6 2 + 6 = 8 3 + 8 = 11 11 + 4 = 15

Inyectar aplica el bloque

 result + element 

a cada elemento en el conjunto. Para el siguiente elemento (“elemento”), el valor devuelto por el bloque es “resultado”. La forma en que lo ha llamado (con un parámetro), “resultado” comienza con el valor de ese parámetro. Entonces el efecto es agregar los elementos.

tldr; inject difiere del map de una manera importante: inject devuelve el valor de la última ejecución del bloque, mientras que el map devuelve la matriz iterada.

Más que eso, el valor de cada ejecución de bloque pasa a la siguiente ejecución a través del primer parámetro ( result en este caso) y puede inicializar ese valor (la parte (0) ).

Su ejemplo anterior podría escribirse usando un map como este:

 result = 0 # initialize result [1, 2, 3, 4].map { |element| result += element } # result => 10 

Mismo efecto pero inject es más conciso aquí.

A menudo encontrará que una asignación ocurre en el bloque del map , mientras que una evaluación ocurre en el bloque de inject .

El método que elija depende del scope que desee para el result . Cuándo no usarlo sería algo como esto:

 result = [1, 2, 3, 4].inject(0) { |x, element| x + element } 

Puede ser como todo, “Mírame, acabo de combinar todo eso en una sola línea”, pero también asignaste memoria temporalmente para x como una variable de cero que no era necesaria porque ya tenías un result con el que trabajar.

 [1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

es equivalente a lo siguiente:

 def my_function(r, e) r+e end a = [1, 2, 3, 4] result = 0 a.each do |value| result = my_function(result, value) end 

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10

En lenguaje simple, está yendo (iterando) a través de esta matriz ( [1,2,3,4] ). Usted iterará a través de esta matriz 4 veces, porque hay 4 elementos (1, 2, 3 y 4). El método de inyección tiene 1 argumento (el número 0), y agregará ese argumento al primer elemento (0 + 1. Esto equivale a 1). 1 se guarda en el “resultado”. Luego, agrega ese resultado (que es 1) al siguiente elemento (1 + 2. Esto es 3). Esto ahora se guardará como resultado. Sigue: 3 + 3 es igual a 6. Y finalmente, 6 + 4 es igual a 10.

Este código no permite la posibilidad de no pasar un valor inicial, pero puede ayudar a explicar lo que está sucediendo.

 def incomplete_inject(enumerable, result) enumerable.each do |item| result = yield(result, item) end result end incomplete_inject([1,2,3,4], 0) {|result, item| result + item} # => 10 

Comience aquí y luego revise todos los métodos que toman bloques. http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject

¿Es el bloque lo que te confunde o por qué tienes un valor en el método? Buena pregunta sin embargo. ¿Cuál es el método del operador allí?

 result.+ 

¿Cómo comienza?

 #inject(0) 

¿Podemos hacer esto?

 [1, 2, 3, 4].inject(0) { |result, element| result.+ element } 

¿Esto funciona?

 [1, 2, 3, 4].inject() { |result = 0, element| result.+ element } 

Verás, estoy construyendo sobre la idea de que simplemente sum todos los elementos de la matriz y arroja un número en la nota que ves en los documentos.

Siempre puedes hacer esto

  [1, 2, 3, 4].each { |element| p element } 

para ver iterar el enumerable de la matriz. Esa es la idea básica.

Es solo que inyectar o reducir le da una nota o un acumulador que se envía.

Podríamos intentar obtener un resultado

 [1, 2, 3, 4].each { |result = 0, element| result + element } 

pero nada vuelve, así que esto solo actúa igual que antes

 [1, 2, 3, 4].each { |result = 0, element| p result + element } 

en el bloque de inspector de elementos.

Hay otra forma de método .inject () que es muy útil [4,5] .inject (&: +) Eso sumrá todo el elemento del área

Simplemente reduce o fold , si está familiarizado con otros idiomas.

Es lo mismo que esto:

 [1,2,3,4].inject(:+) => 10