Outils pour utilisateurs

Outils du site


cours:informatique:dev:programmation_objet_pharo:330_iterateurs

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
cours:informatique:dev:programmation_objet_pharo:330_iterateurs [2022/08/22 11:07] yoanncours:informatique:dev:programmation_objet_pharo:330_iterateurs [2022/08/22 13:48] (Version actuelle) yoann
Ligne 191: Ligne 191:
 Ici, je veux parcourir une collection #( 1 2 3) couplée avec une deuxième collection. J'envoie le message ''with:do:'' à la première collection. Dans mon bloc ''do:'', j'aurai x et y, 2 paramètres. Le premier x, ça sera un élément de la première collection, et y un élément de la deuxième collection. Donc je vais pouvoir multiplier ces éléments entre eux. On obtient dans le Transcript 10, 40 et 90. Et bien évidemment, il faut absolument que les 2 collections aient la même taille avec cet itérateur-là. Ici, je veux parcourir une collection #( 1 2 3) couplée avec une deuxième collection. J'envoie le message ''with:do:'' à la première collection. Dans mon bloc ''do:'', j'aurai x et y, 2 paramètres. Le premier x, ça sera un élément de la première collection, et y un élément de la deuxième collection. Donc je vais pouvoir multiplier ces éléments entre eux. On obtient dans le Transcript 10, 40 et 90. Et bien évidemment, il faut absolument que les 2 collections aient la même taille avec cet itérateur-là.
  
-===== do:separateBy: introduire des séparateurs =====+===== do:separatedBy: introduire des séparateurs =====
  
-On peut avoir d'autres types de parcours. Ici, j'utilise le ''do: separatedBy:''.+On peut avoir d'autres types de parcours: ici, j'utilise le ''do: separatedBy:''.
  
 <code smalltalk> <code smalltalk>
 String streamContents: [ :s | String streamContents: [ :s |
-  #( 'a', 'b',+  #( 'a', 'b', 'c' ) do: [ :each | s << each ] 
 +    separatedBy: [ ', ' ] 
 +
 </code> </code>
  
-J'ai une collection, je vais parcourir chacun des éléments et à chaque fois que j'ai parcouru un élément, je vais évaluer un bloc ici qui correspond à l'affichage d'une virgule. Ça va me permettre de parcourir le A, afficher une virgule, afficher le B, afficher une virgule, afficher le C. A chaque fois entre chaque élément, je vais avoir effectué une action. Ici, j'ai un itérateur qui est "GroupBy", qui me permet de grouper les éléments d'une collection en fonction d'un critère. J'envoie ce message à la collection 123456ici et je récupère en résultat un dictionnaire. Donc tous les éléments qui ont répondu "Faux" à ce critère, le critère c'était "even" c'est les éléments pairs, donc on voit que ça contient bien une collection de tous les éléments impairs. Et tout ce qui a répondu "Vrai", c'est tous les éléments pairs. Quand on a une collection souvent quand on fait des calculs on a tendance à imbriquer des collections dans des collection, et on se retrouve avec des niveaux d'imbrication qui peuvent être importants. Ici, vous avez un exemple construit à la main où on a des collections qui sont imbriquées dans des collections. Ce qu'on aimerait c'est arriver à aplatir la collection, à mettre tous les éléments au même niveau. Pour ça, on a quelque chose de facile en Pharo, on a un itérateur qui s'appelle "flatCollect". C'est-à-dire que je vais parcourir les éléments et construire une nouvelle collection dans laquelle j'ai tout aplati. Donc on obtient bien la collection 123456 dans laquelle on a enlevé tous les niveaux d'imbrication. Le secret, ce n'est pas de vous présenter tous les itérateurs disponibles dans Pharo, ce serait long et fastidieux. L'idée, c'est vraiment de vous montrer qu'il en existe plein et que vous pouvez découvrir vraiment les vôtres en allant lire les méthodes qui existent sur les classes des collections, en allant découvrir ces méthodes. Un exemple simple, c'est de commencer par les itérateurs que vous connaissez. Par exemple, se poser la question "Comment est-ce qu'est implémenté le do?" Je cherche le do dans la hiérarchie des collections, je vais voir qu'il est implémenté dans "SequenceableCollection"toutes les collections séquençables. Donc la méthode "do", elle prend en paramètre un block. Et voici l'implémentation de cette collection. 1 a la taille de la collection do et j'ai un block. Je vais évaluer le block qui est passé en paramètre en lui passant l'élément à l'indice I. Donc c'est tout simple. Les itérateurs sont extrêmement puissants en Pharo, comme on a pu le voir. Toutes les collections supportent ces itérateurs de façon polymorphique. Du point de vue programmeur, on utilise des itérateurs et puis c'est chacune des classes de collections qui vont les implémenter de façon adéquate par rapport à la collection qu'ils représentent. On peut en définir des nouveauxextrêmement intéressants. Je peux définir mes propres itérateurs si j'en ai envie sur les classes de collections. Il y a une subtilité. Pour ceux qui connaissent le Design pattern iterator, en fait la différence c'est que le développeur ne contrôle pas quand il passe à l'élément suivant. C'est la collection, qui en interne, décide de passer à l'élément suivant. On n'envoie pas explicitement le message "next" à l'itérateur. C'est une subtilité pour ceux qui connaissent le Design pattern iterator. En résumé, les itérateurs sont vraiment puissants et un allié fort du programmeur qui vont faciliter l'écriture des programmes. On l'a vu, ça permet d'écrire du code concis, simple et élégant et ça permet de garantir l' encapsulation des données au sein d'une collection.+J'ai une collection, je vais parcourir chacun des éléments et à chaque fois que j'ai parcouru un élément, je vais évaluer un bloc ici qui correspond à l'affichage d'une virgule. 
 + 
 +Ça va me permettre de parcourir le 'a', afficher une virgule, afficher le 'b', afficher une virgule, afficher le 'c'. A chaque fois entre chaque élément, je vais avoir effectué une action. 
 + 
 +===== groupedBy: regrouper des éléments ===== 
 + 
 +Ici, j'ai un itérateur qui est ''groupedBy:'', qui me permet de grouper les éléments d'une collection en fonction d'un critère. 
 + 
 +<code smalltalk> 
 +#( 1 2 3 4 5 6 7 ) groupedBy: #even  
 + 
 +"> an OrderedDictionary(false->#(1 3 5 7) true->#(2 4 6)) " 
 +</code> 
 + 
 +J'envoie le message à la collection #( 1 2 3 4 5 6 7et je récupère en résultat un dictionnaire. Donc tous les éléments qui ont répondu "Faux" à ce critère, le critère c'était "#even" (éléments pairs), donc on voit que ça contient bien une collection de tous les éléments impairs. Et tout ce qui a répondu "Vrai", c'est tous les éléments pairs. 
 + 
 +===== flatCollect: aplatir la collection ===== 
 + 
 +Quand on a une collection souvent quand on fait des calculs on a tendance à imbriquer des collections dans des collection, et on se retrouve avec des niveaux d'imbrication qui peuvent être importants. 
 + 
 +<code smalltalk [enable_lines_numbers="true"]> 
 +#( #(1 2) #(3) #(4) #(5 6)) collect: [ :each | each ] 
 +"> #(#(1 2) #(3) #(4) #(5 6)) " 
 + 
 +#( #(1 2) #(3) #(4) #(5 6)) flatCollect: [ :each | each ] 
 +"> #(1 2 3 4 5 6) " 
 +</code> 
 + 
 +Ici, vous avez un exemple construit à la main où on a des collections qui sont imbriquées dans des collections. Ce qu'on aimerait c'est arriver à aplatir la collection, à mettre tous les éléments au même niveau. 
 + 
 +Pour ça, on a quelque chose de facile en Pharo, on a un itérateur qui s'appelle ''flatCollect:''. C'est-à-dire que je vais parcourir les éléments et construire une nouvelle collection dans laquelle j'ai tout aplati. Donc on obtient bien la collection #(1 2 3 4 5 6) ligne 6 dans laquelle on a enlevé tous les niveaux d'imbrication. 
 + 
 +===== Ouvrir la boîte ===== 
 + 
 +Le secret, ce n'est pas de vous présenter tous les itérateurs disponibles dans Pharo, ce serait long et fastidieux. L'idée, c'est vraiment de vous montrer qu'il en existe plein et que vous pouvez découvrir ceux qui vous seront utiles en allant lire les méthodes qui existent sur les classes des collections, en allant découvrir ces méthodes. 
 + 
 +Un exemple simple, c'est de commencer par les itérateurs que vous connaissez. Par exemple, se poser la question "Comment est-ce qu'est implémenté le ''do:''?" Je cherche le ''do:'' dans la hiérarchie des collections, je vais voir qu'il est implémenté dans "SequenceableCollection" comprenant toutes les collections séquençables.  
 + 
 +Donc la méthode ''do:'', elle prend en paramètre un block. Et voici l'implémentation de cette collection. 
 + 
 +<code smalltalk [enable_line_numbers ="true"]> 
 +do: aBlock  
 +    "Refer to the comment in Collection|do:." 
 +    to: self size do: 
 +        [:index | aBlock value: (self at: index)] 
 +</code> 
 + 
 +Pour chaque élément de la collection (ligne 3) je vais évaluer le block qui est passé en paramètre en lui passant l'élément à l'indice ''index'' (ligne 4). 
 + 
 +===== Résumé ===== 
 + 
 +Les itérateurs sont extrêmement puissants en Pharo, comme on a pu le voir. 
 +  * Toutes les collections supportent ces itérateurs de façon polymorphique. Du point de vue programmeur, on utilise des itérateurs et puis c'est chacune des classes de collections qui vont les implémenter de façon adéquate par rapport à la collection qu'ils représentent. 
 +  * On peut en définir des nouveaux. C'est extrêmement intéressants: je peux définir mes propres itérateurs si j'en ai envie sur les classes de collections. 
 +  * Il y a une subtilité. Pour ceux qui connaissent le Design pattern iterator, en fait la différence c'est que le développeur ne contrôle pas quand il passe à l'élément suivant. C'est la collection, qui en interne, décide de passer à l'élément suivant. On n'envoie pas explicitement le message "next" à l'itérateur. C'est une subtilité pour ceux qui connaissent le Design pattern iterator. 
 + 
 +En résumé, les itérateurs sont vraiment puissants et un allié fort du programmeur qui vont faciliter l'écriture des programmes. On l'a vu, ça permet d'écrire du code concis, simple et élégant et ça permet de garantir l' encapsulation des données au sein d'une collection.
  
cours/informatique/dev/programmation_objet_pharo/330_iterateurs.1661166436.txt.gz · Dernière modification : 2022/08/22 11:07 de yoann