148 votes

Besoin d'une explication simple de la méthode d'injection

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

Je regarde ce code mais mon cerveau n'enregistre pas comment le nombre 10 peut devenir le résultat. Quelqu'un pourrait-il m'expliquer ce qui se passe ici ?

213voto

Drew Olson Points 1107

Vous pouvez considérer le premier argument du bloc comme un accumulateur : le résultat de chaque exécution du bloc est stocké dans l'accumulateur, puis transmis à l'exécution suivante du bloc. Dans le cas du code présenté ci-dessus, vous attribuez par défaut la valeur 0 à l'accumulateur, résultat. Chaque exécution du bloc ajoute le nombre donné au total actuel, puis stocke le résultat dans l'accumulateur. L'appel suivant du bloc a cette nouvelle valeur, l'ajoute, la stocke à nouveau et répète.

À la fin du processus, inject renvoie l'accumulateur, qui dans ce cas est la somme de toutes les valeurs du tableau, soit 10.

Voici un autre exemple simple pour créer un hachage à partir d'un tableau d'objets, avec comme clé leur représentation sous forme de chaîne :

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

Dans ce cas, nous donnons à notre accumulateur la valeur par défaut d'un hachage vide, puis nous le remplissons à chaque fois que le bloc s'exécute. Remarquez que nous devons retourner le hachage à la dernière ligne du bloc, car le résultat du bloc sera stocké dans l'accumulateur.

88voto

Brian Campbell Points 101107

inject prend une valeur de départ (le 0 dans votre exemple), et un bloc, et il exécute ce bloc une fois pour chaque élément de la liste.

  1. Lors de la première itération, il transmet la valeur que vous avez fournie comme valeur de départ, ainsi que le premier élément de la liste, et il enregistre la valeur que votre bloc a retournée (dans ce cas, il s'agit de result + element ).
  2. Il exécute ensuite le bloc à nouveau, en passant le résultat de la première itération comme premier argument, et le deuxième élément de la liste comme deuxième argument, en sauvegardant à nouveau le résultat.
  3. Il continue ainsi jusqu'à ce qu'il ait consommé tous les éléments de la liste.

La façon la plus simple d'expliquer cela est de montrer comment chaque étape fonctionne, pour votre exemple ; il s'agit d'une série d'étapes imaginaires montrant comment ce résultat pourrait être évalué :

[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

30voto

Vishal Nagda Points 679

La syntaxe de la méthode d'injection est la suivante :

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

Résolvons l'exemple ci-dessus, c'est-à-dire

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

qui donne le 10 comme sortie.

Donc, avant de commencer, voyons quelles sont les valeurs stockées dans chaque variable :

résultat = 0 Le zéro vient de inject(valeur) qui est 0

élément = 1 C'est le premier élément du tableau.

Okey ! !! Alors, commençons à comprendre l'exemple ci-dessus

Étape :1 [**_1_**, 2, 3, 4].inject(**0**) { |**0**, _**1**_| **0** + _**1**_ }

Étape :2 [1, **_2_**, 3, 4].inject(0) { |**1**, **_2_**| **1** + **_2_** }

Étape :3 [1, 2, **_3_**, 4].inject(0) { |**3**, **_3_**| **3** + **_3_** }

Étape :4 [1, 2, 3, **_4_**].inject(0) { |**6**, **_4_**| **6** + **_4_** }

Étape :5 [1, 2, 3, 4].inject(0) { |**10**, **_Now no elements left in the array, so it'll return 10 from this step_**| }

Ici Gras-Italique les valeurs sont des éléments récupérés dans le tableau et les valeurs simplement Gras sont les valeurs résultantes.

J'espère que vous comprenez le fonctionnement de la #inject de la méthode #ruby .

19voto

John Topley Points 58789

Le code itère sur les quatre éléments du tableau et ajoute le résultat précédent à l'élément actuel :

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

15voto

Mike Woodhouse Points 27748

Ce qu'ils ont dit, mais notez aussi que vous ne devez pas toujours fournir une "valeur de départ" :

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

est la même chose que

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

Essaie, je vais attendre.

Quand aucun argument n'est passé à injecter, le premier deux sont passés dans la première itération. Dans l'exemple ci-dessus, le résultat est 1 et l'élément est 2 la première fois, donc un appel de moins est fait au bloc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X