Col·leccions i iteradors

De Cacauet Wiki
Salta a la navegació Salta a la cerca

Introducció

  • Una col·lecció és un conjunt d'objectes que es poden recórrer. No especifiquem la manera en com està organitzada l'estructura de dades (pot ser una llista, vector, hash table, arbre, etc). És, per tant, una generalització del concepte d'estructura de dades.
  • Un iterador defineix una interfície amb uns mètodes que permeten accedir als elements d'una col·lecció. Els típics mètodes son:
    • Primer()
    • Ultim()
    • Seguent()
    • Anterior()
    • ...

Alguns enllaços de referència:


En el cas de Python per tal de crear una classe iterable cal implementar els mètodes:

  • __iter__() : retorna un element iterable
  • next() : l'element iterable implementa aquest mètode per passar al següent element.

Per exemple, una llista implementa iteradors. Si examinem els mètodes implementats a la llista:

>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__',
 '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__',
 '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__',
 '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__',
 '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop',
 'remove', 'reverse', 'sort']


Iteradors implícits

Qualsevol bucle tipus "foreach" (p.ex. en PHP) utilitza el patró iterador. En Python ho solem fer al recórrer llistes:

for element in llista:
    print element

"element" cada cop serà un objecte de la llista i en cada iteració avançarem fins el següent element. Encara que no ens adonem, estem utilitzant un objecte iterador de la llista que cada volta avança cap a next().


Iteradors explícits

Una altra manera de recórrer els elements és amb un iterador explícit. Ho podem veure en el següent exemple:

>>> l = [3, 6, 3, 8, 3, 321]
>>> it = l.__iter__()
>>> it
<listiterator object at 0x8bbb88c>
>>> it.next()
3
>>> it.next()
6
>>> it.next()
3
>>> it.next()
8
>>> it.next()
3
>>> it.next()
321
>>> it.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

I si ho volem utilitzar en un while:

l = [3, 6, 3, 8, 3, 321]
it = l.__iter__()
elem = it.next()
while elem:
    print elem
    elem = it.next()

A l'executar-ho obtindrem:

3
6
3
8
3
321
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
StopIteration

Veiem que al final del bucle tenim un problema ja que el darrer element provoca un error (no té cap next()!). Per solventar-ho podem utilitzar un try-catch de l'excepció:

l = [3, 6, 3, 8, 3, 321]
it = l.__iter__()

try:
   elem = it.next()
   while elem:
       print elem,
       elem = it.next()

except StopIteration:
   print "final"

Amb aquest codi, no ens donarà l'error, sinó: (oju, també hem afegit una "," després del print perquè no faci salt de línia):

3 6 3 8 3 321 final