Diziler oluşturabilen bir kütüphaneyi internette ararsanız, diziler ayrık matematik ve bilgisayar biliminin temel kavramı olmasına rağmen neredeyse hiç bulamazsınız.
Bu kısa yazımızda SeqGen isimli dizi üretimi için yazdığım bir kütüphaneye göz atacağız.
Bir dizi (gayri resmi olarak konuşursak), her bir öğenin üretiminin önceki öğeye/öğelere dayandığı bir dizi öğedir (çoğunlukla sayılar).
En temel örnek, pozitif tamsayılardan oluşan basit bir doğrusal dizidir; burada ilk öğe 0 ve sonraki öğe, önceki öğe artı birdir, böylece ikinci öğeyi birinciye bir ekleyerek elde edebiliriz ve üçüncüyü de elde edebiliriz. öğeyi ikinciye bir ekleyerek vb. Doğrusal dizi şu şekilde görünecektir: {0, 1, 2, 3, …, n}
.
Daha karmaşık bir örnek, ilk iki elemanın 0 ve 1 olduğu ve sonraki elemanın önceki iki elemanın toplamı olduğu Fibonacci dizisi olabilir. Fibonacci dizisi şu şekilde görünecektir: {0, 1, 1, 2, 3, 5, 8, 13, 21, …, n}
Yukarıdan bir dizinin iki özellikle tanımlandığını görebiliriz:
2.0_
Bağımlılıklar:SeqGen kütüphanesi Rust programlama dilinde yazılmıştır; Takip etmek için Rust'un kurulu olması gerekir.
2.1_
Proje Oluşturma:SeqGen kütüphanesini kullanmak için yeni bir proje oluşturalım; bunu kargo ile yapabiliriz:
$ cargo new --bin sequence && cd sequence
Şimdi kütüphaneyi projemize bağımlılık olarak ekleyelim:
$ cargo add seqgen
Artık kütüphaneyi kullanmaya hazırız.
SeqGen'de dizi oluşturma süreci, Dizi Nedir bölümünde sonuçlandırdığımız dizinin iki özelliğiyle doğrudan eşleşir; ilk elemanları ve bir sonraki elemanı üreten fonksiyonu (SeqGen'de geçiş fonksiyonu olarak adlandırılır) tanımlamamız gerekir.
Doğrusal diziyi oluşturalım:
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 }); }
Sequence
türü, bir sırayı temsil eden bir yapıdır; bu türdeki ilgili işlevi new()
çağırarak tanımsız yeni bir örnek elde ederiz. Bu tanımsız örnekte, onu tanımlamak için yöntemleri çağırabiliriz.
İlk yöntem, bir öğe vektörünü bağımsız değişken olarak kabul eden ve onu örneğin ilk öğeleri olarak ayarlayan initial_elements()
yöntemidir.
İkinci yöntem, mevcut mevcut öğelerden bir sonraki öğeye geçişi temsil eden bir kapanışı argüman olarak alan transition_function()
yöntemidir.
Bu kapatmanın iki bağımsız değişkene erişimi vardır: birincisi, halihazırda mevcut olan öğeleri temsil eden alive_elements
ve ikincisi, geçerli öğenin üretimdeki dizini olan current_element_index
( usize
türünden). Geçiş fonksiyonunun bir örneği için aşağıdaki tabloya bakın.
Nesildeki Güncel Unsur | canlı_elemanlar | current_element_index |
---|---|---|
| | |
| | |
| | |
| | |
alive_elements
SequencePart
türündedir, bu makalenin ilerleyen kısımlarında SequencePart
türüne göz atacağız
Elemanın indeksi aynı zamanda onun doğrusal sıradaki değeri olduğundan, yukarıdaki örneği şu şekilde basitleştirebiliriz:
use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); }
Burada başlangıç elemanlarını tanımlamamıza ve canlı elemanlara erişmemize gerek yok; sadece dizine ihtiyacımız var (bu durumda adı i
) ve onu geri döndürürüz.
Aynı şekilde Fibonacci dizisini de tanımlayabiliriz:
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 }); }
Fibonacci dizisi üstel olarak büyüdüğü için bu tanımla 187'den fazla eleman üretmek u128
taşmasına neden olacaktır. Daha iyi bir tanım u128
yerine big int kullanır.
Dizimizi tanımladıktan sonra elemanlarına erişebiliriz:
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}"); }
Burada, öğeye değişmez bir referans döndüren nth_element()
yöntemini kullanarak 111. öğeye erişiyoruz (bu durumda &usize
).
linear_seq
değişken hale getirdiğimize dikkat edin. Bunun nedeni nth_element()
yönteminin dizinin canlı öğelerini mutasyona uğratmasıdır.
Bu şekilde dizinin herhangi bir elemanına erişebiliriz ( 0
indeksli elemandan usize::MAX
indeksli elemana kadar.)
Ayrıca herhangi bir Rust yineleyicisi gibi dizi üzerinde yinelemeler yapabiliriz:
use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.for_each(|e| println!("{e}")); }
Bu kod, dizinin tüm öğelerini yazdıracaktır ( 0
öğesinden usize::MAX
öğesine kadar):
$ cargo run -q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
Aşağıdaki kodu kullanarak dizideki tek elemanları elde edebiliriz:
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}")); }
Çıktı:
$ cargo run -q 1 3 5 7 9 11 13 ...
Tanımladığımız dizi yavaştır, yani öğeler gerekmedikçe (yineleme durumunda) veya açıkça talep edilmedikçe ( nth_element()
yöntemi kullanılarak) oluşturulmayacak.
Bazen bir dizinin yalnızca parçalarıyla çalışmamız gerekir, bu durumda dizi parçalarımız olur.
Sıra bölümünün üç türü vardır:
AliveElementsPart
ImmutableRangePart
MutableRangePart
CanlıElemanlarBölümü:
Canlı elemanları, dizideki alive_elements()
yöntemini kullanarak elde edebiliriz:
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} "); } }
Bu kod tüm canlı elemanları yazdıracaktır (bu durumda 0'dan 110'a kadar çünkü 111 elemanı önceden oluşturduk).
Değişmez Aralık Parçası:
Değişmez aralıklar canlı öğelerin aralıklarıdır; diziyi değiştiremezler. Eğer değişmez bir aralık yaratacaksanız ve onun tüm elemanları canlı değilse, bir hata ( DeadRange
hatası) alırsınız.
Result
değerini döndüren range()
yöntemini kullanarak değişmez bir aralık oluşturabiliriz. Ok
değişkeni ImmutableRangePart
ve Err
değişkeni RangeError
. RangeError
InvalidRange
değişkeni olabilir (aralığın başlangıcının bitişinden büyük olması durumunda) veya DeadRange
değişkeni olabilir (aralığın tüm öğelerinin canlı olmaması durumunda):
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}") } }
Bu kod, canlı bir öğe olmadığından DeadRange
hatasıyla panikleyecektir. Bunu aşağıdakilerle düzeltebiliriz:
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}") } }
Burada aralığı geçerli kılmak için 3 öğe oluşturduk.
Değişken Aralık Parçası:
Değişken bir aralık diziyi değiştirebilir (öğeler oluşturabilir).
Bunun gibi değişken bir aralık kullanabiliriz:
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}"); } }
Bu kod 0'dan 110'a kadar olan elemanları yazdıracaktır.
Bu makaleyi sonuna kadar okuduğunuz için teşekkür ederiz ve umarım içinde yararlı bir şeyler bulmuşsunuzdur. Bu kütüphaneyi geliştirebilecek önerileriniz varsa lütfen GitHub'da bir sayı açın ve kütüphaneye katkıda bulunmak istiyorsanız bu harika olur.
Burada da yayınlandı