Итератор (шаблон)

Итератор (на английски: Iterator) е поведенчески шаблон за дизайн, който се използва в обектно-ориентираното програмиране. Итераторът предоставя начин за последователен достъп до елементите на обект, без да е нужна вътрешна информация за обекта. В компютърно програмиране, итератор е обект, който дава възможност на програмиста да преминава през структура от данни. Различни видове итератори често са предоставяни чрез интерфейс контейнер. Въпреки че интерфейсът и семантиката на даден итератор са фиксирани, итераторите често се прилагат по отношение на свързаните с тях структури за изпълнение и често са плътно свързани към контейнера, за да отговарят на семантиката на Итератора. Трябва да се има предвид, че итераторът чете и също така дава достъп до елементите в една структура от данни, но не изпълнява итерация (при тривиално използване на терминологията). Итераторът поведенчески е подобен на курсора на база данни.

Външни итератори и модела итератор

Външно итераторът може да се представи като тип указател, който има две основни операции: Съотнасяне на един конкретен елемент в колекцията на обект и самото му модифициране така, че да сочи към следващия елемент.

В зависимост от езика и предназначението, итераторите могат също да предоставят допълнителни операции или да притежават различни поведения.

Основната цел на итератора е да позволи на потребителя да обработва всеки елемент на структурата от данни, докато изолира потребителя от вътрешната им структура. Итераторният клас обикновено е проектиран в тясно координиране със съответния клас на контейнера. Обикновено, класът-структура от данни осигурява методи за създаване на итератори.

Генератори

Един от начините за прилагане на итератори е да се използва ограничена форма на coroutine, известна катогенератор. За разлика от подпрограма, генераторът може да извика една стойност няколко пъти, вместо само веднъж.

Пример за генератор в Phyton, който връща итератор за номерата на Фибоначи:

def fibonacci(limit):    a, b, c = 0, 1, 0    while c < limit:        yield a        a, b, c = b, a+b, c+1
for number in fibonacci(100): # The generator constructs an iterator    print(number)

Косвени Итератори

Някои обектно-ориентирани езици като C#, C++ (по-нови версии), Delphi (по-нови версии), Go, Java (по-нови версии), Lua, Perl, Python, Ruby предоставят присъщ начин за итериране през елементите на структура от данни без въвеждането на изричен итератор. Итератор действително може да съществува, но ако е така той не е изложен в програмния код.

Косвените итератори най-често се изразяват чрез цикъла "foreach" (или еквивалентен), като в следващия пример на Python:

for value in iterable:    print value

В Python "iterable" е обект, към който може да се прикачи итератор, който след това се повтаря по време на цикъл. Или в други случаи, те могат да бъдат създадени от самия обект, като в този Ruby код:

iterable.each do |value|
  puts value
end

Потоци

Итераторите са полезна абстракция на входящите потоци – те предоставят потенциално безкрайно повтаряне на обект. Няколко езика, като Perl и Python, прилагат потоци като итератори. Алтернативни реализации на поток включват data-drivenезици, като AWK.

Класифициране на итератори

Категории

Итераторите могат да бъдат категоризирани в зависимост от тяхната функционалност. Ето един (неизчерпателен) списък на категории:

КатегорияЕзик
Bidirectional iteratorC++
Forward iteratorC++
Input iteratorC++
Output iteratorC++
Random access iteratorC++
Trivial iteratorC++ (old STL)[1]

Видове

Различни езици или библиотеки, използвани с тези езици определят вида итератор. Някои от тях са:

ВидЕзик
Array iteratorPHP, R[2]
Caching iteratorPHP
Constant iteratorC++,[3] PHP
Directory iteratorPHP, Python
Filter iteratorPHP, R
Limit iteratorPHP
List iteratorJava, R
Recursive array iteratorPHP
XML iteratorPHP

Примери

C++

Езикът C++ имплементира широкото използване на итератори в своята Стандартната библиотека, която осигурява достъп до няколко различни видове итератори, включително препращащи итератори, двупосочни итератори и итератори с произволен достъп. Всички стандартни видове шаблонни контейнери предоставят богат и последователен набор от видове итератори. Синтаксисът на стандартните итератори е проектиран да наподобява този на стандартната C аритметиката с указатели, като операторите ‘* и ‘->’ се използват за показване на елемента, към който итераторът сочи.

C#

Итераторите обикновено се използват, чрез извикване на метода GetEnumerator () на обекта за изпълнение на IEnumerable интерфейса. Класове-контейнери обикновено въвеждат този интерфейс, въпреки това foreach твърдението в C# може да работи с всеки обект, който предоставя такъв метод, дори ако той не се изпълни от IEnumerable.
Следните примери показва използването на итератори в C #:

// explicit versionIEnumerator<MyType> iter = list.GetEnumerator();while (iter.MoveNext())    Console.WriteLine(iter.Current);
// implicit versionforeach (MyType value in list)    Console.WriteLine(value);

Java

Представен в Java JDK 1.2 издание, "java.util.Iterator" интерфейсът позволява итериране на класове. Всеки итератор осигурява "next()" и "hasNext()" метод и може да поддържа "remove()" метод. Итераторите са създадени от съответните съдържащи класове, обичайно от метод наречен "iterator()". Методът "next()" преминава през итератора и връща стойността посочена от итератора. Първият елемент е получен при първото извинкване на следващ "next()". За да се определи кога всички елементи в контейнера са били посетени се използва "hasNext()" метода.

Следващият пример показва проста употреба на итератори:

Iterator iter = list.iterator();
//Iterator<MyType> iter = list.iterator(); in J2SE 5.0
while (iter.hasNext()) {
    System.out.print(iter.next());
    if (iter.hasNext())
      System.out.print(", ");
}

Scala

В Scala, итератори имат богат набор от методи, подобни на колекции, и могат да бъдат използвани директно в for цикли. Всъщност, както итераторите, така и колекциите наследяват от общите черти на – scala.collection.TraversableOnce. Въпреки това, заради богатият набор от методи, които съществуват в Scala колекциите, като например map, collect, filter и т.н., то не се налага често да боравим с итератори директно при програмирането в Scala.

Java итератори и колекции могат автоматично да бъдат превърнати в Scala итератори и колекции, просто чрез добавяне на един-единствен ред

import scala.collection.JavaConversions към файла. Обектът JavaConversions осигурява имплицитни превръщания. Косвените преобразувания са характерни за Scala: методи, които, когато са видими в текущия обхват, автоматично се извикват в най-подходящото място, за да се typecheck-нат когато те иначе не биха.

PHP

PHP 4 въведе foreach конструкцията, подобно на Perl и някои други езици. Това просто дава лесен начин за обхождане на масиви. foreach работи само върху масиви в PHP 4, и ще изведе грешка, когато се опитате да го използвате на променлива с различен тип данни или неинициализирана променлива.В PHP 5, foreach е позволено за итериране върху обект през всички публични членове.

Има два синтаксиса; Вторият е незначително, но полезно разширение на първият.

Пример A

foreach (array_expression as $value) { echo "$value\n"; }

Пример Б

foreach (array_expression as $key => $value) { echo "($key)$value\n"; }

В Пример А итерираме върху масива обозначен с array_expression. На всяко завъртане на цикъла стойността на текущия елемент се записва в $value и вътрешният указател на масива се увеличава с единица (така, че при следващо завъртане на цикъла ще гледа към следващия елемент).

В Пример Б имаме същата функционалност като в Пример А. В допълнение текущият ключ на елемента (в нашият случай array_expression) ще бъде записан в променливата $key при всяко завъртане на цикъла.

Интерфейсът на итератора е предефиниран в PHP 5 и обектите могат да бъдат персонализирани, за да се справят с итерацията.

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;    }}

Тези методи биват използвани в пълна foreach($obj AS $key=>$value)последователност. Методите на итераторите се изпълняват в следния ред:

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

Python

Итераторите в Python са основна част от езика, а и в много случаи са невидими тъй като по презумпция се използва в for (foreach) декларация, в list comprehensions, и в generator expressions. Всички стандартно вградени видове колекции в Пайтън поддържат итерация, както и много класове, които са част от стандартната библиотека. Следващият пример показва типична имплицитна итерация върху последователност:

for value in sequence:

print (value)

Python речниците (форма на асоциативен масив) също могат да бъдат директно итерирани, когато ключовете на речника се връщат; или метода items на речник може да се итерира отново, където той получава съответната ключ, стойност двойка като кортеж:

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

Итераторите могат да се използват и дефинират изрично. За всеки тип итерираща последователност или клас, вградената функция iter () се използва за създаване на итератор обект. Итериращият обект може след това да се итерира с функцията next(), която използва вътрешно метода __next __ (), който връща следващия елемент в контейнера. (Предишното изявление се отнася за Python 3.x. В Python 2.x, метода next() е еквивалентен.). Ще възникне StopIteration exception, когато не са останали повече елементи. Следващият пример показва еквивалентна итерация върху последователност използвайки експлицитни итератори:

it = iter(sequence)while True:    try:        value = it.next() # in Python 2.x        value = next(it) # in Python 3.x    except StopIteration:        break    it = iter(it)    print(value)

Източници

Външни препратки