Iterátor

Az iterátor kifejezés a szoftverfejlesztés területéről származik, és olyan mutatót ír le , amellyel egy halmaz elemeit iterálni lehet (pl. Lista). A kifejezés az iteráció matematikai módszeréből származik . Az iterátort kurzornak szokták nevezni , különösen az adatbázis mezőben .

leírás

Az iterátor egy olyan speciális mutató, amelyet a szoftverfejlesztő egy programon belül használhat egy halmaz elemeihez, más szóval egy listához. Az iterátorok a következő alapelv alapján működnek: "Ha van még egy elem a listában, akkor tegyék elérhetővé."

Leegyszerűsítve ez összehasonlítható egy olyan szöveg elolvasásával, amely szavak listája: „Ha van következő szó, olvassa el. Ha nincs több szó, akkor a szöveg elkészül. ”Az iterációnak nevezett minden hozzáférési lépésben a szövegből pontosan egy szó áll rendelkezésre feldolgozásra.

A programozási gyakorlatban használt sokféle iterátor olyan olvasási hozzáférésen felüli mechanizmusokat biztosít, amelyek eltávolítják a listáról az éppen olvasott elemet, vagy új elemet adnak a listához, ahogyan a szavak beszúrhatók vagy törölhetők is a szöveg szerkesztésekor.

Külső iterátorok és az iterátor tervezési mintája

A külső iterátor egyfajta mutatónak tekinthető, amelynek két elsődleges funkciója van: egy objektumkészletben egy bizonyos elemre hivatkozni (ún. Elem-hozzáférés ), és önmódosítással a halmaz következő elemére mutatni (ún. Elem-átjárás ). A használt programozási nyelvtől és az alkalmazástól függően az iterátorok további funkcionalitással és eltérő viselkedéssel rendelkezhetnek.

Az iterátor fő célja, hogy lehetővé tegye a felhasználó számára, hogy hozzáférjen a készlet bármely eleméhez, miközben elkülöníti őket a halmaz adatszerkezetétől. Ez lehetővé teszi a tömeg számára, hogy minden lehetséges módon kezelje az elemeket, miközben úgy viselkedik a felhasználóval, mintha egy egyszerű sorozat vagy lista lenne. Az iterátor osztály kialakítása szoros együttműködésben történik a konténer osztályával, vagyis a készletével. Általában a container osztály biztosítja az iterátorok létrehozásához használt funkciókat. A ciklusban lévő számlálót (hurokszámlálónak is nevezik) néha hurok iterátornak hívják. Meg kell jegyezni, hogy egy ilyen számláló csak az elem bejárási funkcionalitását térképezi fel, az elem hozzáférési funkcióját nem.

Implicit iterátorok

Számos objektumorientált nyelv, például a Perl , a Python , a C # , a Ruby , valamint az újabb Java és Delphi verziók önmagukban lehetővé teszik az elemek iterációját explicit iterátor objektum használata nélkül. Ez azonban jelen lehet, de nem áll rendelkezésre az adott programozási nyelv kódjában, ha ez így lenne.

Az implicit iterátorok gyakran a foreach parancson vagy annak megfelelőjén keresztül nyilvánulnak meg, amint azt az alábbi Python példa mutatja:

for value in iterable:
    print(value)

A set / list iterablea forciklus segítségével fut át ; minden hurok áthaladásban a változó valueaz aktuális elemet tartalmazza iterable.

Néha az iterátorokat közvetlenül az adatgyűjtési objektumból is létrehozzák, amint az alábbi Ruby-példa mutatja:

iterable.each do |value|
    puts value
end

A eachset / list metódusának meghívása iterableiterátort eredményez, amelyet a dohurok elemenként halad. A huroktest minden elemnél puts valuevégrehajtásra kerül, a változó valueaz aktuális elemet tartalmazza.

Ezt az iterációs stílust belső iterációnak is hívják, mert a kódja teljesen végrehajtásra kerül az iterálandó objektum kontextusában. Ez vezérli az iteráció minden aspektusát, az adott felhasználó vagy programozó csak az egyedi iterációs lépések műveletét végzi anonim szubrutin használatával .

Az úgynevezett listabővítményeket vagy hasonló konstrukciókat támogató nyelvek, a Pythonhoz hasonlóan, az implicit iterátorokat is használják az eredménylista létrehozása során:

names = [person.name for person in roster if person.male]

for ... in ...itt van a mennyiség / lista fölötti "hurok" rosteraz "aktuális elem változóval" person. Minden elemnél ellenőrizzük, hogy érvényes-e egy feltétel (az elemre), vagyis if person.malea mennyiséget kiszűrjük. A többi elem átmásolásra person.namekerül az eredménylistára names- a névlistára.

Néha az implicit, rejtett természet csak részben van jelen. A C ++ programozási nyelv a for_each funkcionalitást a sablonokon keresztül biztosítja , ez implicit iterációt tesz lehetővé.

Az indexelés ellentéte

Az iterátor ellentétben van egy indexrel vagy kulccsal :

  • A társított elem közvetlenül elérhető egy iterátoron keresztül, anélkül, hogy ismerné magát az adatszerkezetet. Index esetén mindig szükség van indexre és adatstruktúrára.
  • Az iterátor csak egy adatstruktúrára érvényes. Az index átvihető más adatstruktúrákba.
  • Az iterátorokat nem lehet sorosítani . Ehhez először indexekké kell átalakítani őket.

A modern, objektumorientált programozási nyelvekben fontosnak bizonyult egy konténer azon képessége, hogy módosítsa önmagát, miközben az elemeken keresztül iterál. Az egyes objektumok és működésük hatásai közötti összefüggések már nem egyértelműek az ilyen nyelveken. Az iterátorokat használják a probléma megoldására.

Generátorok

A generátor a coroutine egy speciális formája, amely minden szekvencia egy vagy több elemét visszaadja minden alkalommal, amikor hívják. Ez a sorrend adott lista lehet, ebben az esetben a generátor nagyrészt megfelel egy iterátornak. Egy generátor csak akkor hívhatja elő a (következő) elemeket, amikor meghívják őket - akkor nincs szüksége létező listára, amint az az iterátorhoz szükséges.

A legtöbb iterátort a generátorok természetes módon és intuitív módon tudják megvalósítani. Mivel a generátorok fenntartják a helyi állapotukat a függvényhívások között, ideálisak komplex állapotjelző iterátorok, például bináris fát bejárók megvalósításához .

Példa egy generátorra, amely elemeket hoz létre ahelyett, hogy felolvasná őket egy listáról:

( Fibonacci szekvencia ; a megfelelő érték "visszatérése" a Python paranccsal yield)

# Ein Generator für die Fibonacci-Folge
def fibonacci(limit_anzahl_elemente):
    a, b = 0, 1

    for _ in range(limit_anzahl_elemente):
        a, b = b, a + b
        yield a

# Die ersten Zahlen der Folge werden berechnet und ausgegeben
for number in fibonacci(100):
    print(number)

Iterátorok különböző programozási nyelveken

C # és más .NET nyelvek

A .NET keretrendszerben szereplő iterátorokat számlálónak nevezzük, és az interfész képviseli őket IEnumerator. IEnumeratornevű függvényt biztosít, amely MoveNext()a halmaz következő eleméhez megy és megmutatja, hogy a vég mikor ért el, valamint egy olyan tulajdonságot, amelyet Currentaz aktuális elem értékének megszerzéséhez hívnak meg. Továbbá egy opcionális Reset()funkciót kínálunk a kezdethez való visszatéréshez. A számláló egy speciális értéket ad vissza inicializálási értékként, amely a kezdetet jelöli. Ezért az inicializálás után MoveNext()végre kell hajtani.

A számlálókat általában egy GetEnumerator()olyan objektum hozza vissza, amely IEnumerablemegvalósítja az interfészt. A C # foreach parancsa minden ilyen funkción működik, még akkor is, ha nem az IEnumerableinterfészt megvalósító objektumból származik . A következő példa az iterátorok egyszerű használatát mutatja be a C # 2.0-ban:

// explizite Version
IEnumerator<MyType> iter = list.GetEnumerator();
while (iter.MoveNext())
    Console.WriteLine(iter.Current);

// implizite Version
foreach (MyType item in list)
    Console.WriteLine(item);

A C # 2.0 támogatja a generátorokat is: a IEnumerable(vagy szintén IEnumerator) visszatérő , de a parancsot yield returnhasználó függvényt a fordító automatikusan átalakítja egy új osztályba, amely megvalósítja a megfelelő interfészt.

C ++

A C ++ programozási nyelv széles körben használja az iterátorokat , és a C ++ szabványos könyvtár segítségével különféle típusú iterátorokat biztosít , például továbbított iterátorokat , kétirányú iterátorokat és véletlen hozzáférésű iterátorokat . A standard tárolóosztályok mindegyikének vannak iterátortípusai. A standard iterátorok szintaxisa a C mutató aritmetikáján alapult . Az operátorok *és ->az elemek hivatkozására szolgálnak. Más operátorok, például ++az elemek közötti navigáláshoz.

Az iterátorokat általában párban használják. Az egyik iterátor az aktuális iterációt jelenti, míg a másik az iteráció végét. Az iterátorokat a megfelelő konténerosztály generálja a standard függvények begin()és segítségével end(). Az iterátor begin()pontokkal tért vissza az első elemre, míg az iterátor end()pontokkal tért vissza egy speciális értékre, amely egyetlen elemre sem hivatkozik. Ha egy iterátort az utolsó elem után helyezünk el, akkor az visszaadja a end(). A következő példa az iterátor tipikus használatát mutatja be a C ++ nyelven:

ContainerType c; // Ein beliebiger Standard-Containertyp, wie std::list<sometype>

for (ContainerType::const_iterator constIt = c.begin(); constIt != c.end(); ++constIt) {
    std::cout << *constIt << '\n';
}

Sokféle iterátor létezik, kissé eltérő viselkedéssel. Nem minden típusú iterátor támogat minden típusú tárolót. Lehetséges azonban, hogy a programozók saját iterátortípusokat definiálhatnak úgy, hogy egy osztályt vezetnek le a sablonból std::iterator. Az iterátor biztonságát külön definiálják a különböző típusokhoz. Az implicit iteráció részben elérhető C ++ nyelven, és a függvények biztosítják std::for_each(), std::copy()és std::accumulate(). Az iterátoroknak azonban mindig szükségük van egy kifejezett objektumra az inicializáláshoz, általában azokra, amelyeket a begin()és end(). Miután ez megtörtént, az iteráció implicit módon történik, az iterátor objektum használata nélkül. Az alábbi példa a for_each használatát mutatja:

// Ein beliebiger Standard-Containertyp jedes ItemType Elements
ContainerType<ItemType> c;

// Funktion, die Zugriff auf jedes Element besitzt
void processItem(const ItemType& i) {
    std::cout << i << '\n';
}

// Eine for-each-Iterationsschleife
std::for_each(c.begin(), c.end(), processItem);

Ugyanez lehet elérni használatával std::copyés std::ostream_iterator:

std::copy(C.begin(), C.end(), std::ostream_iterator<ItemType>(std::cout, "\n"));

Ennek a technikának az egyik korlátja, hogy nem teszi lehetővé a hajótest inline deklarálását. Ezenkívül ehhez egy funkciómutatóra van szükség, amelyet máshol kell deklarálni és paraméterként átadni. Ezt részben kompenzálhatja olyan könyvtárak használata, mint a Boost és a Lambda használata, amelyek függvényobjektumok létrehozására szolgálnak, kapcsolódó infix szintaxissal. Mivel ez a funkció csak külső könyvtárakon keresztül érhető el, különféle megkerülő megoldásokat , más néven megkerülő megoldásokat kell használni.

Jáva

A Java JDK 1.2- ben bevezetett java.util.Iterator felület lehetővé teszi a konténerosztályok iterálását. Mindegyik Iteratormegadja az úgynevezett függvényeket next(), hasNext()valamint egy választható függvényt remove(). Az iterátorokat általában egy úgynevezett függvény iterator()generálja, amelyet a megfelelő tárolóosztály tesz elérhetővé. Az iterátor egy speciális értéket ad vissza inicializálási értékként, amely a kezdetet jelöli. Ezért az inicializálás után next()végre kell hajtani, amely visszaadja az első elemet. A függvény hasNext()segítségével megtudható, hogy az utolsó elem már vissza lett-e adva. A következő példa az iterátorok egyszerű használatát mutatja be a Java-ban:

Iterator iter = list.iterator();

while (iter.hasNext())
    System.out.println(iter.next());

Az ezt támogató gyűjtemények esetében az opcionális szolgáltatás eltávolítja remove()az utoljára elért tételt. A legtöbb ilyen módosítás nem biztonságos. Ezen felül a java.util. Listiterátornak nevezett iterátor ListIterator, amely hasonló felületet biztosít, amely lehetővé teszi az előre és hátra történő iterációt, valamint visszaadja az aktuális elem indexét és be tudja illeszteni az elemet egy adott pozícióba.

A J2SE 5.0- val Iterablebevezették az interfészt , amely foreach értelmében kibővített ciklust jelent. Iterablefüggvényt definiálja iterator(), hogy Iteratorvisszatér Önnek. A kiterjesztett ciklus használatával az előző példa a következőképpen írható:

for (MyType obj: list)
    System.out.print(obj);

MATLAB

A MATLAB támogatja a külső és a belső iterátorokat. Külső iteráció esetén, amelyben a felhasználónak meg kell adnia a következő elemet, több elem definiálható, majd egy for ciklussal futtatható keresztül, amint azt a következő példa mutatja:

% Definition eines an integer arrays
myArray = [1, 3, 5, 7, 11, 13];

for n = myArray
   % ... etwas mit n machen...
   disp(n) %Integerausgabe zur Kommandozeile
end

Belső iteráció esetén a felhasználó átadhat egy műveletet az iterátornak, hogy hozzáférjen egy tömb minden eleméhez. Sok natív operátor és a MATLAB függvény túlterhelt, hogy implicit visszatérési értékként kapjon megfelelő kimeneti tömböt. Ezenkívül a funkciók arrayfunés felhasználhatók cellfuna felhasználó által definiált műveletekre natív és úgynevezett cellatömbökön keresztül .

function simpleFun
% Definition eines an integer arrays
myArray = [1, 3, 5, 7, 11, 13];

% Benutzerdefinierte Operation für jedes Element durchführen
myNewArray = arrayfun(@(a)myCustomFun(a), myArray);

% Arrayausgabe zur Kommandozeile
myNewArray

function outScalar = myCustomFun(inScalar)
% Mit 2 multiplizieren
outScalar = 2 * inScalar;

Alternatív megoldásként kívánatos lehet a tömb tárolási mechanizmusainak elvonása a programozástól az iterátor tervezési mintájának egyedi, objektum-orientált megvalósításának biztosításával. Ilyen, a külső iterációt támogató megvalósítást kínál a MATLAB Központi fájlcsere elem. Ez a tervezési minta az új osztálydefiníciós szintaxis szerint készült, amelyet a MATLAB 7.6 verziójával (R2008a) vezettek be. Továbbá egy egydimenziós sejt tömb végrehajtását List absztrakt adattípus van szükség annak érdekében, hogy tárolja az egyes adattípusok heterogén módon. Ez biztosítja a funkcionalitást feldolgozni egy listát hasNext(), next()és reset()egy közben hurok.

PHP

A PHP4 segítségével egy olyan foreachkonstrukciót vezettek be, amely hasonlóan volt felépítve, mint a Perl és sok más programozási nyelv. Ez a konstrukció lehetővé teszi a tömbök iterálásának egyszerű módját. A foreachparancs csak a PHP4 tömbjeivel működik, és hibát fog okozni, ha egy másik adattípuson vagy egy inicializálatlan változón próbálja használni. A PHP5-ben foreachmegengedett az összes nyilvános tag ismétlése. A következő példa két különböző jelölést mutat be, a második az első jelölés hasznos kiterjesztése:

A. példa
foreach (array_expression as $value)
    echo "$value\n"
B. példa
foreach (array_expression as $key => $value)
    echo "($key)$value\n";

Az A példában egy tömböt, amelyet tömb_kifejezés képvisel, ismétlődik. Minden hurok átadásakor $valuehozzárendelik a tömb elem értékét, és a tömb belső mutatóját eggyel előre tolják. Ez azt jelenti, hogy a következő tömb elem a következő ciklus passzban kerül visszaadásra. A B példa ugyanolyan funkcionalitással rendelkezik, mint az A példa. Ezenkívül az elem indexét minden hurkoláskor hozzárendelik a változóhoz $key.

A PHP5-ben az iterátor interfész előre definiált, az objektumok megváltoztathatók az iteráció kezeléséhez.

class MyIterator implements Iterator {
    private $var = array();

    public function __construct($array) {
        if (is_array($array)) {
            $this->var = $array;
        }
    }

    public function rewind() {
        echo "rewinding\n";
        reset($this->var);
    }

    public function current() {
        $var = current($this->var);
        echo "current: $var\n";
        return $var;
    }

    public function key() {
        $var = key($this->var);
        echo "key: $var\n";
        return $var;
    }

    public function next() {
        $var = next($this->var);
        echo "next: $var\n";
        return $var;
    }

    public function valid() {
        $var = $this->current() !== false;
        echo "valid: {$var}\n";
        return $var;
    }
}

Ezeket a funkciókat teljes foreach($obj as $key=>$value)sorrendben használják. Az iterátor módszerek a következő sorrendben futnak:

  1. rewind()
  2. while valid()
     {
          2.1 current() in $value
          2.3 key() in $key
          2.4 next()
     }

piton

A Pythonban szereplő iterátorok a nyelv alapvető részét képviselik, de gyakran implicit módon használják őket, és így láthatatlanul el vannak rejtve a nyelvi parancsokban. Ilyen parancsok pl. B. for(foreach) úgynevezett listamegértésekben és generátor kifejezésekben. A Python összes szekvenciális alaptípusa, valamint a szabványos könyvtár sok osztálya támogatja az iterációkat. A következő példa egy szekvencia tipikus iterációját mutatja:

for value in sequence:
    print(value)

A Python szótárak , az asszociatív tömb egyik formája lehetővé teszi, hogy közvetlenül az önmagán ismétlődjön, amikor az úgynevezett szótár kulcsokat visszaadják. Azt is meg lehet megismételhetjük az elemek funkciója a szótárban, ha visszatér az értékeket kulcs és érték szerint a következő példát:

for key in dictionary:
    value = dictionary[key]
    print(key, value)
for key, value in dictionary.items():
    print(key, value)

A Pythonban található itterátorok szintén kifejezetten definiálhatók és használhatók. Minden iterálható szekvenciatípushoz vagy minden iterálható osztályhoz rendelkezésre áll a beépített iter()függvény iterátor objektum létrehozására. Az iterátor objektummal el lehet navigálni a következő elemhez a függvényekkel next(), vagy __next__(). Ha eléri a készlet végét, StopIterationhiba lép fel. A következő példa a kifejezett iterátorok egyenértékű megvalósítását mutatja:

it = iter(sequence)

while True:
    try:
        value = it.next()
    except StopIteration:
        break

    print(value)

Minden felhasználó által definiált osztály támogathatja a szokásos iterációt, ha _iter__()meghatároztak egy olyan funkciót, amely iterátor objektumot generál, akkor az iterátornak meg kell __next__()határoznia egy függvényt, amely visszatér a következő elemhez. A Python generátorok implementálják ezt az iterációs protokollt.

Rubin

Az iterátorok megvalósítása a Ruby-ban eltér a legtöbb programozási nyelvtől: Az összes iteráció azt az elképzelést követi, hogy az úgynevezett visszahívási lezárásokon átmenjenek a konténer módszerek. Ily módon a Ruby nemcsak az iterátorok alapvető funkcióit valósítja meg, hanem számos iterátor tervezési mintát is feltérképez, például: B. úgynevezett függvény-leképezés , szűrők és úgynevezett redukció .

A Ruby egy alternatív szintaxist is támogat az iteráció minden egyes alapfunkciójához:

(0...42).each do |n|
    puts n
end

… És…

for n in 0...42
    puts n
end

vagy még rövidebb

42.times do |n|
    puts n
end

Lásd még

web Linkek

Egyéni bizonyíték

  1. std::for_each()
  2. std::copy()
  3. std::accumulate()
  4. std::ostream_iterator
  5. java.util.Iterator Java API specifikáció
  6. next() Java API specifikáció
  7. hasNext() Java API specifikáció
  8. remove() Java API specifikáció
  9. java.util.List Java API specifikáció
  10. java.util.ListIterator Java API specifikáció
  11. Iterable Java API specifikáció
  12. iterator() Java API specifikáció
  13. Tervezési minta: Iterátor (viselkedés)