Iterador

format_list_bulleted Contenido keyboard_arrow_down
ImprimirCitar
En el cálculo, un objeto que permite a un programador atravesar un contenedor, en particular listas

En la programación de computadoras, un iterador es un objeto que permite a un programador atravesar un contenedor, particularmente listas. A menudo se proporcionan varios tipos de iteradores a través de la interfaz de un contenedor. Aunque la interfaz y la semántica de un iterador dado son fijas, los iteradores a menudo se implementan en términos de las estructuras subyacentes a la implementación de un contenedor y, a menudo, están estrechamente acoplados al contenedor para permitir la semántica operativa del iterador. Un iterador realiza el recorrido y también da acceso a los elementos de datos en un contenedor, pero no realiza la iteración (es decir, no sin cierta libertad significativa con ese concepto o con un uso trivial de la terminología).

El comportamiento de un iterador es similar al de un cursor de base de datos. Los iteradores datan del lenguaje de programación CLU en 1974.

Descripción

Iteradores internos

Los iteradores internos son funciones de orden superior (a menudo toman funciones anónimas, pero no necesariamente) como map(), reduce(), etc., que implementan el recorrido a través de un contenedor, aplicando la función dada a cada elemento a su vez. Un ejemplo podría ser la función map de Python:

dígitos = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]squared_digits = mapa()lambda x: x#2, dígitos)# La iteración sobre este iterador resultaría en 0, 1, 4, 9, 16,..., 81.

Iteradores externos y el patrón de iteradores

Se puede pensar en un iterador externo como un tipo de puntero que tiene dos operaciones principales: hacer referencia a un elemento en particular en la colección de objetos (llamado acceso a elementos) y modificarse a sí mismo para que apunte al objeto. siguiente elemento (llamado recorrido de elementos). También debe haber una forma de crear un iterador para que apunte a algún primer elemento, así como alguna forma de determinar cuándo el iterador ha agotado todos los elementos del contenedor. Según el lenguaje y el uso previsto, los iteradores también pueden proporcionar operaciones adicionales o exhibir diferentes comportamientos.

El propósito principal de un iterador es permitir que un usuario procese cada elemento de un contenedor mientras lo aísla de la estructura interna del contenedor. Esto permite que el contenedor almacene elementos de la forma que desee, al tiempo que permite que el usuario lo trate como si fuera una simple secuencia o lista. Una clase de iterador generalmente se diseña en estrecha coordinación con la clase de contenedor correspondiente. Normalmente, el contenedor proporciona los métodos para crear iteradores.

A veces, un contador de bucles también se denomina iterador de bucles. Sin embargo, un contador de bucle solo proporciona la funcionalidad transversal y no la funcionalidad de acceso a elementos.

Generadores

Una forma de implementar iteradores es usar una forma restringida de corrutina, conocida como generador. En contraste con una subrutina, una corrutina generadora puede dar valores a su llamador varias veces, en lugar de regresar solo una vez. La mayoría de los iteradores se pueden expresar de forma natural como generadores, pero debido a que los generadores conservan su estado local entre invocaciones, son particularmente adecuados para iteradores complicados y con estado, como los que atraviesan árboles. Existen sutiles diferencias y distinciones en el uso de los términos "generador" e "iterador", que varían entre autores e idiomas. En Python, un generador es un constructor de iteradores: una función que devuelve un iterador. A continuación se muestra un ejemplo de un generador de Python que devuelve un iterador para los números de Fibonacci utilizando la instrucción yield de Python:

def fibonacci()límite): a, b = 0, 1 para ¿Qué? dentro rango()límite): rendimiento a a, b = b, a + bpara Número dentro fibonacci()100): # El generador construye un iterador impresión()Número)

Iteradores implícitos

Algunos lenguajes orientados a objetos como C#, C++ (versiones posteriores), Delphi (versiones posteriores), Go, Java (versiones posteriores), Lua, Perl, Python, Ruby proporcionan una forma intrínseca de iterar a través de los elementos de un objeto contenedor sin la introducción de un objeto iterador explícito. Un objeto iterador real puede existir en la realidad, pero si lo hace, no está expuesto dentro del código fuente del lenguaje.

Los iteradores implícitos a menudo se manifiestan mediante un "foreach" (o equivalente), como en el siguiente ejemplo de Python:

para valor dentro iterable: impresión()valor)

En Python, un iterable es un objeto que se puede convertir en un iterador, que luego se itera durante el ciclo for; esto se hace implícitamente.

O en otras ocasiones pueden ser creados por el propio objeto de la colección, como en este ejemplo de Ruby:

iterable.cada uno do SilenciovalorSilencio puts valorfinal

Este estilo de iteración a veces se denomina "iteración interna" porque su código se ejecuta completamente dentro del contexto del objeto iterable (que controla todos los aspectos de la iteración), y el programador solo proporciona la operación para ejecutar en cada paso (usando una función anónima).

Los lenguajes que admiten listas de comprensión o construcciones similares también pueden utilizar iteradores implícitos durante la construcción de la lista de resultados, como en Python:

nombres = [persona.Nombre para persona dentro Lista si persona.Hombre]

A veces, la naturaleza oculta implícita es solo parcial. El lenguaje C++ tiene algunas plantillas de funciones para la iteración implícita, como for_each(). Estas funciones aún requieren objetos de iterador explícitos como su entrada inicial, pero la iteración posterior no expone un objeto de iterador al usuario.

Transmisiones

Los iteradores son una abstracción útil de los flujos de entrada: proporcionan un objeto iterable (pero no necesariamente indexable) potencialmente infinito. Varios lenguajes, como Perl y Python, implementan flujos como iteradores. En Python, los iteradores son objetos que representan flujos de datos. Las implementaciones alternativas de stream incluyen lenguajes basados en datos, como AWK y sed.

En contraste con la indexación

En los lenguajes de procedimiento, es común usar el operador de subíndice y un contador de bucle para recorrer todos los elementos en una secuencia, como una matriz. Aunque la indexación también se puede usar con algunos contenedores orientados a objetos, el uso de iteradores puede tener algunas ventajas:

  • Contar bucles no son adecuados a todas las estructuras de datos, en particular a estructuras de datos sin acceso aleatorio o lento, como listas o árboles.
  • Los analfabetos pueden proporcionar una manera consistente de iterar en estructuras de datos de todo tipo, y por lo tanto hacer el código más legible, reutilizable y menos sensible a un cambio en la estructura de datos.
  • Un iterador puede imponer restricciones adicionales al acceso, tales como asegurar que los elementos no pueden ser saltados o que un elemento previamente visitado no puede ser accedido por segunda vez.
  • Un iterador puede permitir que el objeto contenedor sea modificado sin invalidar el iterador. Por ejemplo, una vez que un iterador haya avanzado más allá del primer elemento, puede ser posible insertar elementos adicionales en el comienzo del contenedor con resultados previsibles. Con indexación esto es problemático ya que los números índice deben cambiar.

La capacidad de modificar un contenedor mientras se itera a través de sus elementos se ha vuelto necesaria en la programación moderna orientada a objetos, donde las interrelaciones entre los objetos y los efectos de las operaciones pueden no ser obvias. Al usar un iterador, uno está aislado de este tipo de consecuencias. Sin embargo, esta afirmación debe tomarse con pinzas, porque la mayoría de las veces, por razones de eficiencia, la implementación del iterador está tan estrechamente ligada al contenedor que impide la modificación del contenedor subyacente sin invalidarse.

Para los contenedores que pueden moverse por sus datos en la memoria, la única forma de no invalidar el iterador es, para el contenedor, realizar un seguimiento de todos los iteradores actualmente activos y actualizarlos sobre la marcha. Dado que la cantidad de iteradores en un momento dado puede ser arbitrariamente grande en comparación con el tamaño del contenedor vinculado, actualizarlos todos afectará drásticamente la garantía de complejidad en las operaciones del contenedor.

Una forma alternativa de mantener el número de actualizaciones vinculado en relación con el tamaño del contenedor sería usar una especie de mecanismo de control, es decir, una colección de punteros indirectos a los elementos del contenedor que deben actualizarse con el contenedor. y deje que los iteradores apunten a estos identificadores en lugar de directamente a los elementos de datos. Pero este enfoque tendrá un impacto negativo en el rendimiento del iterador, ya que debe efectuar un seguimiento de doble puntero para acceder al elemento de datos real. Por lo general, esto no es deseable, porque muchos algoritmos que utilizan los iteradores invocan la operación de acceso a datos de los iteradores con más frecuencia que el método avanzado. Por lo tanto, es especialmente importante tener iteradores con acceso a datos muy eficiente.

En general, siempre se trata de una compensación entre seguridad (los iteradores siempre son válidos) y eficiencia. La mayoría de las veces, la seguridad adicional no vale el precio de eficiencia que se paga por ella. Usar un contenedor alternativo (por ejemplo, una lista enlazada individualmente en lugar de un vector) sería una mejor opción (globalmente más eficiente) si se necesita la estabilidad de los iteradores.

Clasificación de iteradores

Categorías de iteradores

Los iteradores se pueden clasificar según su funcionalidad. Aquí hay una lista (no exhaustiva) de categorías de iteradores:

CategoríaIdiomas
Iterador bidireccionalC++
Adelante iteradorC++
Input iteratorC++
Output iteratorC++
Iterador de acceso aleatorioC++
Trivial iteratorC++ (old STL)

Tipos de iteradores

Diferentes lenguajes o bibliotecas usadas con estos lenguajes definen tipos de iterador. Algunos de ellos son

TipoIdiomas
Array iteratorPHP, R
Caching iteratorPHP
Constante iteradorC+++, PHP
Directorio iteradorPHP, Python
Filtro iteradorPHP, R
Limite el iteradorPHP
List iteratorJava, R
Recursive array iteratorPHP
Iterador XMLPHP

En diferentes lenguajes de programación

C# y otros lenguajes.NET

Los iteradores en.NET Framework se denominan "enumeradores" y representado por la interfaz IEnumerator. IEnumerator proporciona un método MoveNext(), que avanza al siguiente elemento e indica si se ha llegado al final de la colección; una propiedad Current, para obtener el valor del elemento al que se apunta actualmente; y un método Reset() opcional, para rebobinar el enumerador a su posición inicial. El enumerador apunta inicialmente a un valor especial antes del primer elemento, por lo que se requiere una llamada a MoveNext() para comenzar a iterar.

Los enumeradores normalmente se obtienen llamando al método GetEnumerator() de un objeto que implementa la interfaz IEnumerable. Las clases de contenedores normalmente implementan esta interfaz. Sin embargo, la declaración foreach en C# puede operar en cualquier objeto que proporcione dicho método, incluso si no implementa IEnumerable (tipo pato). Ambas interfaces se ampliaron a versiones genéricas en.NET 2.0.

A continuación se muestra un uso sencillo de los iteradores en C# 2.0:

// Versión explícitaIEnumerator.Mi tipo iter = lista.GetEnumerator();mientras ()iter.Mover()) Consola.WriteLine()iter.Corriente);// versión implícitaen adelante ()Mi tipo valor dentro lista) Consola.WriteLine()valor);

C# 2.0 también admite generadores: un método que se declara que devuelve IEnumerator (o IEnumerable), pero utiliza el "rendimiento de retorno" declaración para producir una secuencia de elementos en lugar de devolver una instancia de objeto, el compilador la transformará en una nueva clase que implemente la interfaz adecuada.

C++

El lenguaje C++ hace un amplio uso de iteradores en su biblioteca estándar y describe varias categorías de iteradores que difieren en el repertorio de operaciones que permiten. Estos incluyen iteradores directos, iteradores bidireccionales e iteradores de acceso aleatorio, en orden creciente de posibilidades. Todos los tipos de plantillas de contenedores estándar proporcionan iteradores de una de estas categorías. Los iteradores generalizan punteros a elementos de una matriz (que de hecho se pueden usar como iteradores), y su sintaxis está diseñada para parecerse a la aritmética de punteros C, donde * y -> se utilizan para hacer referencia al elemento al que apunta el iterador y los operadores aritméticos de puntero como ++ se utilizan para modificar los iteradores en el recorrido de un contenedor.

El recorrido mediante iteradores suele implicar un solo iterador variable y dos iteradores fijos que sirven para delimitar un rango que se va a recorrer. La distancia entre los iteradores limitantes, en términos del número de aplicaciones del operador ++ necesarias para transformar el límite inferior en superior, es igual al número de elementos en el rango designado; el número de valores de iterador distintos involucrados es uno más que eso. Por convención, el iterador de límite inferior "apunta a" el primer elemento en el rango, mientras que el iterador de límite superior no apunta a ningún elemento en el rango, sino más bien más allá del final del rango. Para atravesar un contenedor completo, el método begin() proporciona el límite inferior y end() el límite superior. Este último no hace referencia a ningún elemento del contenedor, pero es un valor de iterador válido con el que se puede comparar.

El siguiente ejemplo muestra un uso típico de un iterador.

std::vector.int Temas;Temas.push_back()5); // Apéndice valor entero '5' al vector 'Artículos'.Temas.push_back()2); // Apéndice valor entero '2' al vector 'items'.Temas.push_back()9); // Apéndice valor entero '9' al vector 'Artículos'.para ()auto es = Temas.comenzar(); es ! Temas.final(); ++es) {} // Itear a través de 'Artículos'. std::Cout .. *es; // Y valor de impresión de 'Artículos' para el índice actual.}// En C++11, se puede hacer lo mismo sin utilizar ningún iterator:para ()auto x : Temas) {} std::Cout .. x; // Valor de impresión de cada elemento 'x' de 'Artículos'.}// Tanto para los bucles imprimir "529".

Los tipos de iteradores están separados de los tipos de contenedores con los que se usan, aunque los dos se usan a menudo juntos. La categoría del iterador (y, por lo tanto, las operaciones definidas para él) generalmente depende del tipo de contenedor, por ejemplo, las matrices o los vectores brindan iteradores de acceso aleatorio, pero los conjuntos (que usan una estructura vinculada como implementación) solo brindan iteradores bidireccionales. Un mismo tipo de contenedor puede tener más de un tipo de iterador asociado; por ejemplo, el tipo de contenedor std::vector<T> permite el recorrido utilizando punteros (en bruto) a sus elementos (de tipo *<T>), o valores de un tipo especial std::vector<T>::iterator, y se proporciona otro tipo para "iteradores inversos", cuyas operaciones se definen de tal manera que un algoritmo que realiza un recorrido habitual (hacia adelante) en realidad lo hará en orden inverso cuando se le llame con iteradores inversos. La mayoría de los contenedores también proporcionan un tipo const_iterator separado, para el cual las operaciones que permitirían cambiar los valores señalados no están definidas intencionalmente.

El recorrido simple de un objeto contenedor o un rango de sus elementos (incluida la modificación de esos elementos a menos que se use un const_iterator) se puede realizar usando solo iteradores. Pero los tipos de contenedores también pueden proporcionar métodos como insert o erase que modifican la estructura del propio contenedor; estos son métodos de la clase contenedora, pero además requieren uno o más valores de iterador para especificar la operación deseada. Si bien es posible tener múltiples iteradores apuntando al mismo contenedor simultáneamente, las operaciones de modificación de la estructura pueden invalidar ciertos valores de iterador (el estándar especifica para cada caso si esto puede ser así); el uso de un iterador invalidado es un error que conducirá a un comportamiento indefinido, y tales errores no necesitan ser señalados por el sistema de tiempo de ejecución.

La iteración implícita también es parcialmente compatible con C++ mediante el uso de plantillas de funciones estándar, como std::for_each(), std::copia() y std::acumular().

Cuando se usan, deben inicializarse con iteradores existentes, generalmente begin y end, que definen el rango sobre el cual ocurre la iteración. Pero ningún objeto iterador explícito se expone posteriormente a medida que avanza la iteración. Este ejemplo muestra el uso de for_each.

Container Tipo.Tipo de artículo c; // Cualquier tipo de contenedor estándar de elementos ItemType.vacío ProcessItem()const Tipo de artículo" i) {} // Función que procesará cada elemento de la colección. std::Cout .. i .. std::endl;}std::for_each()c.comenzar(), c.final(), ProcessItem); // A for-each iteration loop.

Se puede lograr lo mismo usando std::copy, pasando un valor std::ostream_iterator como tercer iterador:

std::Copia()c.comenzar(), c.final(), std::ostream_iterator.Tipo de artículo()std::Cout, "n"));

Desde C++11, la sintaxis de la función lambda se puede usar para especificar que la operación se itere en línea, evitando la necesidad de definir una función con nombre. Aquí hay un ejemplo de iteración for-each usando una función lambda:

Container Tipo.Tipo de artículo c; // Cualquier tipo de contenedor estándar de elementos ItemType.// Un bucle de iteración para cada uno con una función de lambda.std::for_each()c.comenzar(), c.final(), [](const Tipo de artículo" i) {} std::Cout .. i .. std::endl; });

Java

Introducida en el lanzamiento de Java JDK 1.2, la interfaz java.util.Iterator permite la iteración de clases contenedoras. Cada Iterator proporciona un método next() y hasNext(), y puede admitir opcionalmente un método remove(). Los iteradores son creados por la clase contenedora correspondiente, normalmente por un método llamado iterator().

El método next() avanza el iterador y devuelve el valor señalado por el iterador. El primer elemento se obtiene con la primera llamada a next(). Para determinar cuándo se han visitado todos los elementos del contenedor, se utiliza el método de prueba hasNext(). El siguiente ejemplo muestra un uso simple de iteradores:

Iterator iter = lista.iterator();// Iterador realizadoMiTipo empírico iter = list.iterator(); // en J2SE 5.0mientras ()iter.haSiguiente()) {} Sistema.Fuera..impresión()iter.siguiente()); si ()iter.haSiguiente()) Sistema.Fuera..impresión()", ");}

Para mostrar que hasNext() se puede llamar repetidamente, lo usamos para insertar comas entre los elementos pero no después del último elemento.

Este enfoque no separa correctamente la operación de avance del acceso real a los datos. Si el elemento de datos debe usarse más de una vez para cada avance, debe almacenarse en una variable temporal. Cuando se necesita un avance sin acceso a los datos (es decir, para omitir un elemento de datos determinado), el acceso se realiza de todos modos, aunque en este caso se ignora el valor devuelto.

Para los tipos de colección que lo admiten, el método remove() del iterador elimina el elemento visitado más recientemente del contenedor mientras mantiene el iterador utilizable. Agregar o eliminar elementos llamando a los métodos del contenedor (también desde el mismo hilo) hace que el iterador quede inutilizable. Un intento de obtener el siguiente elemento arroja la excepción. También se lanza una excepción si no quedan más elementos (hasNext() ha devuelto previamente falso).

Además, para java.util.List hay un java.util.ListIterator con una API similar pero que permite la iteración hacia adelante y hacia atrás, proporciona su índice actual en la lista y permite establecer el elemento de la lista en su posición.

La versión J2SE 5.0 de Java introdujo la interfaz Iterable para admitir un bucle mejorado for (foreach) para iterar sobre colecciones y matrices. Iterable define el método iterator() que devuelve un Iterator. Usando el bucle for mejorado, el ejemplo anterior se puede reescribir como

para ()Mi tipo obj : lista) {} Sistema.Fuera..impresión()obj);}

Algunos contenedores también usan la clase Enumeration más antigua (desde 1.0). Proporciona métodos hasMoreElements() y nextElement() pero no tiene métodos para modificar el contenedor.

Escala

En Scala, los iteradores tienen un amplio conjunto de métodos similares a las colecciones y se pueden usar directamente en bucles for. De hecho, tanto los iteradores como las colecciones heredan de un rasgo base común: scala.collection.TraversableOnce. Sin embargo, debido al amplio conjunto de métodos disponibles en la biblioteca de colecciones de Scala, como map, collect, filter, etc., a menudo es no es necesario tratar directamente con los iteradores al programar en Scala.

Los iteradores y colecciones de Java se pueden convertir automáticamente en iteradores y colecciones de Scala, respectivamente, simplemente agregando la línea única

importación scala.colección.JavaConversiones.¿Qué?

al archivo. El objeto JavaConversions proporciona conversiones implícitas para hacer esto. Las conversiones implícitas son una característica de Scala: métodos que, cuando están visibles en el alcance actual, automáticamente insertan llamadas a sí mismos en expresiones relevantes en el lugar apropiado para hacer que verifiquen el tipo cuando de otro modo no lo harían.

MATLAB

MATLAB admite la iteración implícita externa e interna mediante el uso de "native" matrices o matrices cell. En el caso de una iteración externa en la que el usuario tiene la responsabilidad de avanzar en el recorrido y solicitar los siguientes elementos, se puede definir un conjunto de elementos dentro de una estructura de almacenamiento de matriz y recorrer los elementos utilizando el bucle for. construir. Por ejemplo,

% Define una matriz de enterosMyArray = [1,3,5,7,11,13];para n = MyArray %... haz algo con n disp()n) % Echo integer to Command Windowfinal

recorre una matriz de enteros utilizando la palabra clave for.

En el caso de una iteración interna en la que el usuario puede proporcionar una operación al iterador para realizar sobre cada elemento de una colección, muchos operadores integrados y funciones de MATLAB están sobrecargados para ejecutar sobre cada elemento de una matriz y devolver una correspondiente matriz de salida implícitamente. Además, las funciones arrayfun y cellfun se pueden aprovechar para realizar operaciones personalizadas o definidas por el usuario sobre "nativos" matrices y matrices cell respectivamente. Por ejemplo,

función simple Diversión% Define una matriz de enterosMyArray = [1,3,5,7,11,13];% Realizar una operación personalizada sobre cada elemento myNewArray = arrayfun(@)a)myCustomFun()a),MyArray);% Echo resultante array a Command WindowmyNewArrayfunción outScalar = myCustomFun()inScalar)% Simplemente multiplicado por 2outScalar = 2*inScalar;

define una función principal simpleFun que implícitamente aplica la subfunción personalizada myCustomFun a cada elemento de una matriz usando la función integrada arrayfun.

Alternativamente, puede ser deseable abstraer los mecanismos del contenedor de almacenamiento de matriz del usuario mediante la definición de una implementación personalizada de MATLAB orientada a objetos del patrón Iterator. Una implementación de este tipo que admite la iteración externa se muestra en Patrón de diseño de elemento de intercambio de archivos central de MATLAB: iterador (comportamiento). Esto está escrito en la nueva sintaxis de definición de clase introducida con el software MATLAB versión 7.6 (R2008a) y presenta una realización de matriz de cell unidimensional de List Abstract Data Type (ADT) como mecanismo para almacenar un conjunto heterogéneo (en tipo de datos) de elementos. Proporciona la funcionalidad para el recorrido de lista hacia adelante explícito con los métodos hasNext(), next() y reset() para usar en un mientras-bucle.

PHP

El bucle foreach de PHP se introdujo en la versión 4.0 y se hizo compatible con los objetos como valores en la versión 4.0 Beta 4. Sin embargo, se agregó soporte para iteradores en PHP 5 a través de la introducción del Traversable interfaz. Las dos interfaces principales para la implementación en scripts PHP que permiten la iteración de objetos a través del bucle foreach son Iterator e IteratorAggregate. Este último no requiere que la clase de implementación declare todos los métodos requeridos, sino que implementa un método de acceso (getIterator) que devuelve una instancia de Traversable. La biblioteca estándar de PHP proporciona varias clases para trabajar con iteradores especiales. PHP también admite generadores desde 5.5.

La implementación más simple es envolver una matriz, esto puede ser útil para sugerencias de tipo y ocultación de información.

namespace Wikipedia Iterator;final clase ArrayIterator extensiones Iterator{} privado array $array; público función __construir()array $array) {} Esto-array = $array; } público función rebobinado(): vacío {} eco 'rebobinado ' , PHP_EOL; reseteo()Esto-array); } público función corriente() {} $value = corriente()Esto-array); eco "current: {}$value}", PHP_EOL; retorno $value; } público función clave() {} $key = clave()Esto-array); eco "key: {}$key}", PHP_EOL; retorno $key; } público función siguiente() {} $value = siguiente()Esto-array); eco "Anexo: {}$value}", PHP_EOL; retorno $value; } público función válido(): bool {} $válido = Esto-corriente() ! falso; eco 'válido: ', ()$válido ? 'verdad ' : 'falso '), PHP_EOL; retorno $válido; }}

Todos los métodos de la clase de ejemplo se utilizan durante la ejecución de un bucle foreach completo (foreach ($iterator as $key => $current) {}). Los métodos del iterador se ejecutan en el siguiente orden:

  1. $iterator->rewind() asegura que la estructura interna comience desde el principio.
  2. $iterator->valid() retornos verdadero en este ejemplo.
  3. $iterator->current() valor devuelto se almacena en $value.
  4. $iterator->key() valor devuelto se almacena en $key.
  5. $iterator->next() avanza al siguiente elemento de la estructura interna.
  6. $iterator->valid() retornos falso y el bucle es abortado.

El siguiente ejemplo ilustra una clase de PHP que implementa la interfaz Traversable, que podría incluirse en una clase IteratorIterator para actuar sobre los datos antes de devolverlos a foreach. El uso junto con la constante MYSQLI_USE_RESULT permite que los scripts PHP iteren conjuntos de resultados con miles de millones de filas con muy poco uso de memoria. Estas características no son exclusivas de PHP ni de sus implementaciones de clase MySQL (por ejemplo, la clase PDOStatement también implementa la interfaz Traversable).

mysqli_report()MYSQLI_REPORT_ERROR Silencio MYSQLI_REPORT_STRICT);$mysqli = nuevo mysqli()host.example.com ', Nombre de usuario ', 'password ', Database_name ');// La clase mysqli_result que es devuelta por el método llamada implementa la interfaz Traversable interna.en adelante ()$mysqli-query()'SELECT `a`, `b`, `c` from `table` ', MYSQLI_USE_RESULT) como Ganancias) {} // Actúa en la fila devuelta, que es un array asociativo.}

Pitón

Los iteradores en Python son una parte fundamental del lenguaje y, en muchos casos, pasan desapercibidos, ya que se usan implícitamente en la declaración for (foreach), en listas de comprensión y en generadores de expresiones. Todos los tipos de colección integrados estándar de Python admiten la iteración, así como muchas clases que forman parte de la biblioteca estándar. El siguiente ejemplo muestra una iteración implícita típica sobre una secuencia:

para valor dentro secuencia: impresión()valor)

Los diccionarios de Python (una forma de matriz asociativa) también se pueden iterar directamente cuando se devuelven las claves del diccionario; o el método items() de un diccionario se puede iterar sobre donde produce los pares clave-valor correspondientes como una tupla:

para clave dentro diccionario: valor = diccionario[clave] impresión()clave, valor)
para clave, valor dentro diccionario.Temas(): impresión()clave, valor)

Sin embargo, los iteradores pueden usarse y definirse explícitamente. Para cualquier clase o tipo de secuencia iterable, la función incorporada iter() se usa para crear un objeto iterador. El objeto iterador se puede repetir con la función next(), que utiliza el método __next__() internamente, que devuelve el siguiente elemento del contenedor. (La declaración anterior se aplica a Python 3.x. En Python 2.x, el método next() es equivalente). Se generará una excepción StopIteration cuando no haya más elementos quedan El siguiente ejemplo muestra una iteración equivalente sobre una secuencia utilizando iteradores explícitos:

es = iter()secuencia)mientras Cierto.: Prueba: valor = es.siguiente() # En Python 2.x valor = siguiente()es) # En Python 3.x excepto StopIteration: descanso impresión()valor)

Cualquier clase definida por el usuario puede admitir la iteración estándar (ya sea implícita o explícita) definiendo un método __iter__() que devuelve un objeto iterador. Luego, el objeto iterador debe definir un método __next__() que devuelva el siguiente elemento.

Los generadores de Python implementan este protocolo de iteración.

Raku

Los iteradores en Raku son una parte fundamental del lenguaje, aunque normalmente los usuarios no tienen que preocuparse por los iteradores. Su uso está oculto detrás de las API de iteración, como la instrucción for, map, grep, indexación de listas con .[$idx], etc

El siguiente ejemplo muestra una iteración implícita típica sobre una colección de valores:

# @values = 1, 2, 3;
para @values - $value {}
 Di: $value}
# OutPUT:# 1# 2# 3

Los hashes de Raku también se pueden iterar directamente; esto produce objetos clave-valor Pair. El método kv se puede invocar en el hash para iterar sobre la clave y los valores; el método keys para iterar sobre las claves hash; y el método values para iterar sobre los valores hash.

# %word-to-number = 'uno ' = 1, 'dos ' = 2, Tres ' = 3;
para %word-to-number - $pair {}
 Di: $pair;
}
# OutPUT:# 3 = # 3# one = # 1# 2 = confianza 2para %word-to-number.kv - $key, $value {}
 Di: "$key: $value" }
# OutPUT:# three: 3# one: 1# 2: 2para %word-to-number.llaves - $key {}
 Di: "$key = prenda" ~ %word-to-number{}$key};
}
# OutPUT:# 3 = # 3# one = # 1# 2 = confianza 2

Sin embargo, los iteradores pueden usarse y definirse explícitamente. Para cualquier tipo iterable, existen varios métodos que controlan diferentes aspectos del proceso de iteración. Por ejemplo, se supone que el método iterator devolverá un objeto Iterator, y se supone que el método pull-one producirá y devolverá el siguiente valor si es posible, o devolver el valor centinela IterationEnd si no se pueden producir más valores. El siguiente ejemplo muestra una iteración equivalente sobre una colección usando iteradores explícitos:

# @values = 1, 2, 3;
# $it:= @values.iterator; # grab iterator for @valuesbucle {}
 # $value:= $it.Tira-uno; # El próximo valor de la iteración último si $value == IteraciónEnd; # Stop if we reached iteration's end Di: $value;
}
# OutPUT:# 1# 2# 3

Todos los tipos iterables en Raku componen el rol Iterable, el rol Iterator o ambos. El Iterable es bastante simple y solo requiere que el iterador sea implementado por la clase que lo compone. El Iterator es más complejo y proporciona una serie de métodos como pull-one, que permite una operación más fina de iteración en varios contextos, como agregar o eliminar elementos, o saltándolos para acceder a otros elementos. Por lo tanto, cualquier clase definida por el usuario puede soportar la iteración estándar al componer estos roles e implementar los métodos iterator y/o pull-one.

La clase DNA representa una hebra de ADN e implementa el iterador al componer el rol Iterable. La hebra de ADN se divide en un grupo de trinucleótidos cuando se itera sobre:

subset Strand de Str Donde {.partido()/^^^ $$/) y.chars%% 3 };
clase ADN ¿Sí? Iterable {}
 tiene $.chain;
 método nuevo()Strand:D Cadenaauto.Bendito::Cadena}

 método iterator()ADN:D:){ $.chain.comb.rotor()3).iterator }
};

para ADN.nuevo()'GATTACATA '♪
.Di:}
# OutPUT:# (G A T)# (T A C)# (A T A)Di: ADN.nuevo()'GATTACATA ').mapa(*.Únase).Únase()' ');
# OutPUT:# GAT-TAC-ATA

La clase Repeater compone los roles Iterable y Iterator:

clase Repetidor ¿Sí? Iterable ¿Sí? Iterator {}
 tiene Cualquier $.item es necesarios;
 tiene Int $.times es necesarios;
 tiene Int ¡Cuenta! = 1;

 multi método nuevo()Tema, Horas de $auto.Bendito::Tema,:Horas de $;
}

 método iterator {} auto }
 método Tira-uno(... Mu){
 si ¡Cuenta!. ¡$! veces {}
 ¡Cuenta! += 1;
 retorno ¡$$!}
 más {}
 retorno IteraciónEnd}
}
}

para Repetidor.nuevo()"Hola", 3♪
.Di:}

# OutPUT:# Hola.# Hola.# Hola.

Rubí

Ruby implementa los iteradores de forma bastante diferente; todas las iteraciones se realizan mediante el paso de cierres de devolución de llamada a métodos de contenedor; de esta manera, Ruby no solo implementa la iteración básica, sino también varios patrones de iteración como el mapeo de funciones, filtros y reducción. Ruby también admite una sintaxis alternativa para el método de iteración básico each, los siguientes tres ejemplos son equivalentes:

()0...42).cada uno do SilencionSilencio puts nfinal

... y...

para n dentro 0...42 puts nfinal

o incluso más corto

42.veces do SilencionSilencio puts nfinal

Ruby también puede iterar sobre listas fijas usando Enumerators y llamando a su método #next o haciendo un para cada uno de ellos, como se indicó anteriormente.

Óxido

Con Rust se puede iterar sobre elementos de vectores o crear iteradores propios. Cada iterador tiene adaptadores (map, filter, skip, take,...).

para n dentro 0..42 {} ¡Imprimir!()"{}", n);}

Debajo de la función fibonacci() devuelve un iterador personalizado.

para i dentro fibonacci().Patrón()4).Toma.()4) {} ¡Imprimir!()"{}", i);}

Contenido relacionado

Número computable

En matemáticas, números computables son los números reales que se pueden calcular con cualquier precisión deseada mediante un algoritmo de terminación...

Vecindad (teoría de grafos)

En teoría de grafos, un vértice adyacente, vecindad o neighbourhood de un vértice v en un gráfico es un vértice que está conectado a v por una arista....

Unidad de ejecución

En ingeniería informática, una unidad de ejecución es una parte de la unidad central de procesamiento que realiza las operaciones y cálculos según las...
Más resultados...
Tamaño del texto:
undoredo
format_boldformat_italicformat_underlinedstrikethrough_ssuperscriptsubscriptlink
save