C# 11 – List and Slice Pattern
Merhaba,
Gün geçmiyor ki, C# yeteneklerine yeni bir nitelik kazandırmasın 🙂 Bu içeriğimizde, C# 11 ile gelen özellikler arasında nacizane olarak oldukça kullanışlı gördüğüm List Pattern üzerine odaklanacak ve gelen bu yeniliğin tüm özelliklerini değerlendiriyor olacağız.
List Pattern, elimizdeki List koleksiyonlarının ya da dizilerinin değerlerini farklı bir diziyle eşleştirebilmemizi ve bu eşleştirme neticesinde sonucu boolean olarak edinebilmemizi sağlayarak şartlı kodlarda üst düzey yaklaşım sergilememize olanak tanıyan bir yeniliktir.
Bu pattern’a dair daha detaylı konuşabilmek için öncelikle aşağıdaki örnekler üzerinden konuyu somutlaştırarak mevzuya girelim.
int[] array = { 1, 2, 3 }; Console.WriteLine(array is [1, 2, 3]); //true Console.WriteLine(array is [1]); //false Console.WriteLine(array is [1, 2]); //false Console.WriteLine(array is [3, 4, 5]); //false
Yukarıdaki kod bloğunu incelerseniz eğer 1. satırda tanımlanan dizi(esasında bir koleksiyonda olabilirdi) alt satırlarda is
operatörü eşliğinde farklı dizisel değerlerle karşılaştırılmakta ve sonuç boolean olarak elde edilmektedir.
İşte bu list pattern’ın ta kendisidir. Dikkat ederseniz, ilgili pattern’ı uygulayabilmek için köşeli parantezler [
]
semantik olarak bizlere eşlik etmektedir.
Bu şekilde bir kullanımla ilgili koleksiyonun kümülatif olarak verilen diziyle aynı olup olmadığı kontrol edilmektedir. Halbuki bizler koleksiyon içerisinde verilen değerlerin olup olmadığını yahut sıra gözetmeksizin farklı verilerin varlığını kontrol etmek isteyebiliriz. İşte böyle bir durumda aşağıdaki gibi discard operatöründen de istifade edebilmekteyiz.
int[] array = { 1, 2, 3 }; Console.WriteLine(array is [_, 2, _]); //true Console.WriteLine(array is [_, 1, _]); //false Console.WriteLine(array is [1, 2, _]); //true Console.WriteLine(array is [_, _, _, 3, 4, 5]); //false Console.WriteLine(array is [_, _, _]); //true
Görüldüğü üzere discard operatörü ile bir nebze koleksiyon verilerinin karşılaştırılmasında esneklik sağlamış olsak da hala değerlendirmenin sıralı bir şekilde olmasından kurtulabilmiş değiliz. Bunun için aşağıdaki gibi slice pattern’dan da faydalanabiliriz.
int[] array = { 1, 2, 3 }; Console.WriteLine(array is [_, .., 2, _]); //true Console.WriteLine(array is [1, 2, ..]); //true Console.WriteLine(array is [_, .., _, 3, 4, 5]);//false Console.WriteLine(array is [_, _, _]); //true Console.WriteLine(array is [..]); //true
Slice pattern’da kullanılan range operatörü sayesinde sıralamanın herhangi bir yerinde istenilen değere karşılık değerlendirme yapılabilir ya da kaynak koleksiyondaki veri sayısıyla/uzunluğuyla ilgilenilmediği taktirde yine bu range pattern’dan istifade edilebilir.
Bu arada unutulmamalıdır ki, slice pattern bir dizi içerisinde yalnızca tek bir kez kullanılmakta aksi taktirde derleyici hatası alınmaktadır.
Esasında şuana kadar yaptığımız tüm örneklendirmelerde list pattern içerisinde sabit değerler kullandığımızdan dolayı farkında olmadan constant pattern kullanmış bulunmaktayız. Normal şartlarda bu sabitliğe olan bağımlılığı değiştirebilir ve relational pattern gibi kalıpları da uygulayabiliriz.
int[] array = { 1, 2, 3 }; Console.WriteLine(array is [_, >= 2, < (3 * 5)]); //true Console.WriteLine(array is [_, .., < (3 * 5)]); //true
Görüldüğü üzere list pattern, özellikle elimizdeki koleksiyonel verilerde yapı düzenini gözetmeksizin yapılacak karşılaştırmalarda oldukça etkili bir özelliktir. Nihayetinde elimizdeki koleksiyondan verileri bir objeye dönüştürme gereği duymaksızın direkt olarak bu pattern sayesinde hızlıca kontrollerimizi sağlayabilir ve operasyonlarımızı gerçekleştirebiliriz.
Şimdi son olarak Microsoft’un dökümanlarında(bknz : list patterns) konuya dair oldukça güzel bir örneği burada modelleyip ardından içeriğimizi sonlandıralım istiyorum.
Bir bankada, herhangi bir müşterinin belirli tarihler aralığındaki işlem bilgilerini içeren metin dosyasının aşağıdaki şekilde alıntılandığını varsayalım.
Tarih | İşlem | Açıklama | Kime | Ücret |
---|---|---|---|---|
18.05.2022 | FAST | Deposito ödeme | Hilmi Celayir | 1500₺ |
12.05.2022 | FAST | Apartman aidat | Faruk Eczaneci | 50₺ |
10.05.2022 | EFT | Mutfak dolabı taksidi | 1050₺ | |
09.05.2022 | EFT | Sigorta ödemesi | 850₺ | |
09.05.2022 | FAST | Köy sandığı | Cemil Yılmaz | 50₺ |
Yukarıdaki veri kümesine göz atarsanız eğer ilgili müşterinin yaptığı tüm para transferlerini görmekteyiz. Burada para transferini gerçekleştiren müşterimiz ise transferin gerçekleştirildiği kişinin ‘Kime’ kolonunda ismi yazılıyorken, dışarıdan müşteriye gerçekleştiriliyorsa eğer o zaman boş bırakılmakta, herhangi bir veri yazılmamaktadır. Para transferi sürecinde ‘FAST’te %2, ‘EFT’de ise %3 komisyon alındığını varsayarsak eğer böyle bir veri kümesi üzerinde list pattern eşliğinde, discard pattern, constant pattern ve var pattern‘ı aşağıdaki gibi kullanıp toplam bakiyeyi aşağıdaki gibi hesaplayabiliriz.
object[] bankProcess1 = { "18.05.2022", "FAST", "Deposito ödeme", "Hilmi Celayir", 1500 }; object[] bankProcess2 = { "12.05.2022", "FAST", "Apartman aidat", "Faruk Eczaneci", 50 }; object[] bankProcess3 = { "10.05.2022", "EFT", "Mutfak dolabı taksidi", 1050 }; object[] bankProcess4 = { "09.05.2022", "EFT", "Sigorta ödemesi", 850 }; object[] bankProcess5 = { "09.05.2022", "FAST", "Köy sandığı", "Cemil Yılmaz", 50 }; List<object[]> bankProcesses = new() { bankProcess1, bankProcess2, bankProcess3, bankProcess4, bankProcess5 }; float balance = 0; foreach (object[] bankProcess in bankProcesses) { balance += bankProcess switch { [_, "FAST", _, _, int amount] => -(amount + (amount * 2 / 100)), [_, "EFT", _, _, int amount] => -(amount + (amount * 3 / 100)), [_, "FAST", .., int amount] => amount, [_, "EFT", .., int amount] => amount, _ => 0 }; } Console.WriteLine($"Bakiye : {balance}");
Ayrıca list pattern’ı var pattern ile birlikte aşağıdaki gibi kullanıp adedi bilinmeyen tüm verileri ayrı bir dizi olarak elde edebilmekteyiz.
var array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; if (array is [1, 2, .. var vals, 9]) Console.WriteLine(String.Join(",", vals));
Yukarıdaki kaynak koda göz atarsanız eğer
.. var vals
şeklinde iki pattern’ı kombinlersek eğer bizlere aralıktaki tüm değerleri dizi olarak getirecektir.
Nihai olarak,
Görüldüğü üzere list pattern’ı koleksiyonel veriler üzerinde dizisel eşleştirme verileriyle gönül rahatlığıyla kullanabilir ve kodunuza esneklik kazandırabilirsiniz.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…