Einführung: Wenn Sie im Internet nach einer Bibliothek suchen, die Sequenzen generieren kann, werden Sie kaum eine finden, obwohl Sequenzen ein Kernkonzept der diskreten Mathematik und Informatik sind. In diesem kurzen Artikel werfen wir einen Blick auf eine Bibliothek namens , die ich für die Sequenzgenerierung geschrieben habe. SeqGen Was ist eine Sequenz? Eine Sequenz (informell gesprochen) ist eine Menge von Elementen (hauptsächlich Zahlen), wobei die Produktion jedes Elements auf dem/den vorhergehenden Element(en) basiert. Das einfachste Beispiel ist eine einfache lineare Folge positiver Ganzzahlen, bei der das erste Element 0 und das nächste Element das vorhergehende Element plus eins ist. Wir können also das zweite Element erhalten, indem wir eins zum ersten addieren, und wir können das dritte Element erhalten Element, indem man eins zum zweiten hinzufügt, und so weiter. Die lineare Folge würde so aussehen: . {0, 1, 2, 3, …, n} Ein komplexeres Beispiel könnte die Fibonacci-Folge sein, bei der die ersten beiden Elemente 0 und 1 sind und das nächste Element die Summe der beiden vorhergehenden Elemente ist. Die Fibonacci-Folge würde so aussehen: {0, 1, 1, 2, 3, 5, 8, 13, 21, …, n} Wir können oben erkennen, dass eine Sequenz mit zwei Eigenschaften definiert ist: Die ersten Elemente Eine Funktion, die das nächste Element erzeugt Nutzung der Bibliothek: 2.0_ Abhängigkeiten: Die SeqGen-Bibliothek ist in der Programmiersprache Rust geschrieben; Um weiterzumachen, muss sein. Rust installiert 2.1_ Ein Projekt erstellen: Lassen Sie uns ein neues Projekt erstellen, um die SeqGen-Bibliothek zu verwenden. Wir können dies mit Fracht tun: $ cargo new --bin sequence && cd sequence Fügen wir nun die Bibliothek als Abhängigkeit zu unserem Projekt hinzu: $ cargo add seqgen Jetzt können wir die Bibliothek nutzen. Erstellen einer Sequenz: In SeqGen wird der Sequenzerstellungsprozess direkt den beiden Eigenschaften der Sequenz zugeordnet, die wir im Abschnitt „Was ist eine Sequenz“ festgestellt haben; Wir müssen die Anfangselemente und die Funktion definieren, die das nächste Element erzeugt (in SeqGen Übergangsfunktion genannt). Erstellen wir die lineare Folge: 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 }); } Der Typ ist eine Struktur, die eine Sequenz darstellt. Durch den Aufruf der zugehörigen Funktion für diesen Typ erhalten wir eine neue Instanz, die undefiniert ist. Für diese undefinierte Instanz können wir Methoden aufrufen, um sie zu definieren. Sequence new() Die erste Methode ist , die einen Vektor von Elementen als Argument akzeptiert und ihn als Anfangselemente der Instanz festlegt. initial_elements() Die zweite Methode ist , die als Argument einen Abschluss verwendet, der den Übergang von den aktuell verfügbaren Elementen zum nächsten Element darstellt. transition_function() Dieser Abschluss hat Zugriff auf zwei Argumente: Das erste ist , das die aktuell verfügbaren Elemente darstellt, und das zweite ist (vom Typ ), das der Index des aktuellen Elements in der Generierung ist. Eine Darstellung der Übergangsfunktion finden Sie in der folgenden Tabelle. alive_elements current_element_index usize Aktuelles Element in der Generation lebendige_elemente aktueller_element_index 1 [0] 1 2 [0, 1] 2 3 [0, 1, 2] 3 n [0, 1, 2, 3, …, n] n ist vom Typ . Wir werden uns den Typ später in diesem Artikel ansehen alive_elements SequencePart SequencePart Da der Index des Elements auch sein Wert in der linearen Folge ist, können wir das obige Beispiel wie folgt vereinfachen: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); } Hier müssen wir die anfänglichen Elemente nicht definieren und wir benötigen keinen Zugriff auf die Live-Elemente. Wir brauchen nur den Index (der in diesem Fall heißt) und geben ihn einfach zurück. i Auf die gleiche Weise können wir die Fibonacci-Folge definieren: 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 }); } Da die Fibonacci-Folge exponentiell wächst, führt die Generierung von mehr als 187 Elementen mit dieser Definition zu einem Überlauf von . Eine bessere Definition würde big int anstelle von verwenden. u128 u128 : Verwendung der Sequenz Nachdem wir unsere Sequenz definiert haben, können wir auf ihre Elemente zugreifen: 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}"); } Hier greifen wir auf das 111. Element mit der Methode zu, die einen unveränderlichen Verweis auf das Element zurückgibt (in diesem Fall ). nth_element() &usize Beachten Sie, dass wir veränderbar gemacht haben. Das liegt daran, dass die Methode die aktiven Elemente der Sequenz mutiert. linear_seq nth_element() Auf diese Weise können wir auf jedes Element der Sequenz zugreifen (vom Element mit dem Index bis zum Element mit dem Index ). 0 usize::MAX Wir können die Sequenz auch wie jeder Rust-Iterator durchlaufen: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.for_each(|e| println!("{e}")); } Dieser Code gibt alle Elemente der Sequenz aus (vom Element bis zum Element ): 0 usize::MAX $ cargo run -q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ... Mit dem folgenden Code können wir die ungeraden Elemente aus der Sequenz abrufen: 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}")); } Ausgabe: $ cargo run -q 1 3 5 7 9 11 13 ... Die von uns definierte Sequenz ist verzögert, was bedeutet, dass die Elemente nur dann generiert werden, wenn sie benötigt werden (im Falle einer Iteration) oder explizit angefordert werden (mit der Methode ). nth_element() : Arbeiten mit Teilen der Sequenz Manchmal müssen wir nur mit Teilen einer Sequenz arbeiten, in diesem Fall handelt es sich um Sequenzteile. Es gibt drei Arten des Sequenzteils: AliveElementsPart ImmutableRangePart MutableRangePart AliveElementsPart: Wir können die Live-Elemente mit der Methode für die Sequenz abrufen: 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} "); } } Dieser Code gibt alle aktiven Elemente aus (in diesem Fall 0 bis 110, da wir 111 Elemente vorab generiert haben). ImmutableRangePart: Unveränderliche Bereiche sind Bereiche der lebendigen Elemente; Sie können die Sequenz nicht mutieren. Wenn Sie einen unveränderlichen Bereich erstellen und nicht alle seine Elemente aktiv sind, erhalten Sie eine Fehlermeldung ( Fehler). DeadRange Mit der Methode können wir einen unveränderlichen Bereich erstellen, der ein zurückgibt. Die Variante ist und die Variante ist . Der könnte die Variante sein (falls der Anfang des Bereichs größer als sein Ende ist), oder er könnte Variante sein (falls nicht alle Elemente des Bereichs aktiv sind): 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}") } } Dieser Code löst einen Fehler aus, da kein aktives Element vorhanden ist. Wir können dies wie folgt korrigieren: 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}") } } Hier haben wir drei Elemente generiert, um den Bereich gültig zu machen. MutableRangePart: Ein veränderlicher Bereich kann die Sequenz verändern (Elemente generieren). Wir können einen veränderlichen Bereich wie folgt verwenden: 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}"); } } Dieser Code druckt die Elemente von 0 bis 110. Einführung: Vielen Dank, dass Sie diesen Artikel bis zum Ende gelesen haben, und ich hoffe, Sie haben etwas Nützliches darin gefunden. Wenn Sie Vorschläge zur Verbesserung dieser Bibliothek haben, . Wenn Sie möchten, wäre das wunderbar. öffnen Sie bitte ein Problem auf GitHub zur Bibliothek beitragen Auch veröffentlicht hier