Introducción: Si busca en Internet una biblioteca que pueda generar secuencias, difícilmente podrá encontrarla, aunque las secuencias son un concepto central de las matemáticas discretas y la informática. En este breve artículo, veremos una biblioteca que escribí para la generación de secuencias llamada . SeqGen ¿Qué es una secuencia? Una secuencia (informalmente hablando) es un conjunto de elementos (principalmente números) donde la producción de cada elemento se basa en los elementos anteriores. El ejemplo más básico es una secuencia lineal simple de números enteros positivos donde el primer elemento es 0 y el siguiente elemento es el elemento anterior más uno, por lo que podemos obtener el segundo elemento sumando uno al primero, y podemos obtener el tercero. elemento añadiendo uno al segundo, y así sucesivamente. La secuencia lineal se vería así: . {0, 1, 2, 3, …, n} Un ejemplo más complejo podría ser la secuencia de Fibonacci donde los dos primeros elementos son 0 y 1, y el siguiente elemento es la suma de los dos elementos anteriores. La secuencia de Fibonacci se vería así: {0, 1, 1, 2, 3, 5, 8, 13, 21, …, n} Podemos notar desde arriba que una secuencia se define con dos propiedades: Los elementos iniciales Una función que produce el siguiente elemento. Usando la biblioteca: 2.0_ Dependencias: La biblioteca SeqGen está escrita en el lenguaje de programación Rust; Para realizar el seguimiento, es necesario tener . instalado Rust 2.1_ Creando un proyecto: Creemos un nuevo proyecto para usar la biblioteca SeqGen; podemos hacerlo con carga: $ cargo new --bin sequence && cd sequence Ahora, agreguemos la biblioteca como una dependencia a nuestro proyecto: $ cargo add seqgen Ahora estamos listos para usar la biblioteca. Creando una secuencia: En SeqGen, el proceso de creación de secuencias se asigna directamente a las dos propiedades de la secuencia que concluimos en la sección ¿Qué es una secuencia? Tenemos que definir los elementos iniciales y la función que produce el siguiente elemento (llamada función de transición en SeqGen). Creemos la secuencia lineal: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .initial_elements(vec![0]) .transition_function(|alive_elements, current_element_index| { alive_elements.last_element().unwrap() + 1 }); } El tipo es una estructura que representa una secuencia; Al llamar a la función asociada en este tipo, obtenemos una nueva instancia que no está definida. En esta instancia indefinida, podemos llamar a métodos para definirla. Sequence new() El primer método es que acepta un vector de elementos como argumento y lo establece como los elementos iniciales de la instancia. initial_elements() El segundo método es que toma como argumento un cierre que representa la transición de los elementos actualmente disponibles al siguiente elemento. transition_function() Este cierre tiene acceso a dos argumentos: el primero es que representa los elementos disponibles actualmente, y el segundo es (de tipo ) que es el índice del elemento actual en generación. Consulte la siguiente tabla para ver una ilustración de la función de transición. alive_elements current_element_index usize Elemento actual en generación elementos_vivos índice_elemento_actual 1 [0] 1 2 [0, 1] 2 3 [0, 1, 2] 3 n [0, 1, 2, 3, …, n] n es de tipo , veremos el tipo más adelante en este artículo. alive_elements SequencePart SequencePart Dado que el índice del elemento también es su valor en la secuencia lineal, podemos simplificar el ejemplo anterior a: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); } Aquí, no necesitamos definir los elementos iniciales y no necesitamos acceder a los elementos activos; solo necesitamos el índice (que en este caso se llama ) y simplemente lo devolvemos. i De la misma manera podemos definir la secuencia de Fibonacci: use seqgen::prelude::*; fn main() { let fib_seq = Sequence::new() .initial_elements(vec![0, 1_u128]) .transition_function(|alive_elements, i| { let x = alive_elements.nth_element(i - 1).unwrap(); let y = alive_elements.nth_element(i - 2).unwrap(); x + y }); } Dado que la secuencia de Fibonacci crece exponencialmente, generar más de 187 elementos con esta definición hará que se desborde. Una mejor definición usaría big int en lugar de . u128 u128 : Usando la secuencia Después de que definimos nuestra secuencia, podemos acceder a sus elementos: use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let some_element = linear_seq.nth_element(111); println!("{some_element}"); } Aquí, accedemos al elemento 111 utilizando el método que devuelve una referencia inmutable al elemento ( en este caso). nth_element() &usize Observe que hicimos que fuera mutable. Esto se debe a que el método mutará los elementos vivos de la secuencia. linear_seq nth_element() De esta forma, podemos acceder a cualquier elemento de la secuencia (desde el elemento con índice hasta el elemento con índice .) 0 usize::MAX También podemos iterar sobre la secuencia como cualquier iterador de Rust: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.for_each(|e| println!("{e}")); } Este código imprimirá todos los elementos de la secuencia (desde el elemento hasta el elemento ): 0 usize::MAX $ cargo run -q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ... Podemos obtener los elementos impares de la secuencia usando el siguiente código: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let odd_elements = linear_seq.filter(|e| e % 2 != 0); odd_elements.for_each(|e| println!("{e}")); } Producción: $ cargo run -q 1 3 5 7 9 11 13 ... La secuencia que definimos es diferida, lo que significa que los elementos no se generarán a menos que sean necesarios (en caso de iteración) o se soliciten explícitamente (usando el método ). nth_element() : Trabajar con partes de la secuencia A veces, solo necesitamos trabajar con partes de una secuencia; en este caso, tenemos partes de secuencia. Hay tres tipos de parte de secuencia: AliveElementsPart ImmutableRangePart MutableRangePart AliveElementsParte: Podemos obtener los elementos activos usando el método en la secuencia: alive_elements() use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .transition_function(|_, i| i) .pre_generate(111); let alive_elements = linear_seq.alive_elements(); for alive_element in alive_elements { print!("{alive_element} "); } } Este código imprimirá todos los elementos activos (de 0 a 110 en este caso porque generamos previamente 111 elementos). Parte de rango inmutable: Los rangos inmutables son rangos de elementos vivos; no pueden mutar la secuencia. Si crea un rango inmutable y no todos sus elementos están vivos, obtendrá un error (error ). DeadRange Podemos crear un rango inmutable usando el método que devuelve un . La variante es y la variante es . El podría ser la variante (en caso de que el inicio del rango sea mayor que su final), o podría ser la variante (en caso de que no todos los elementos del rango estén vivos): range() Result Ok ImmutableRangePart Err RangeError RangeError InvalidRange DeadRange use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } } Este código generará pánico con el error porque no hay ningún elemento vivo. Podemos corregir esto con lo siguiente: DeadRange use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.generate(3); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } } Aquí, generamos 3 elementos para que el rango sea válido. Parte de rango mutable: Un rango mutable puede mutar la secuencia (generar elementos). Podemos usar un rango mutable como este: use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let mut_range = linear_seq.range_mut(0, 111).unwrap(); for e in mut_range { println!("{e}"); } } Este código imprimirá los elementos del 0 al 110. Producción: Gracias por leer este artículo hasta el final y espero que hayas encontrado algo útil en él. Si tiene alguna sugerencia que pueda mejorar esta biblioteca, y, si desea , sería maravilloso. abra una edición en GitHub contribuir a la biblioteca También publicado aquí