Photo by Riku Lu / Unsplash

Lazy Collection / Sequence

Swift Aug 5, 2023

Lazy Sequence'ler tüm öğelerinde değil, ihtiyaç halinde çağırıldığı dizilerdir. Özellikle büyük diziler ile çalışırken bazı durumlar için performansı olumlu etkisi olacaktır.

Örneğin:

let numbers = Array(1...100000)

let doubled = numbers.map { $0 * 2 }

Yukarıdaki map fonksiyonu tüm değerleri için 2 ile çarpma işlemini yapacaktır. Ancak tamamına değil sadece belli bir koşula uyan değerlere yapmak isteyebiliriz. Bu durumda lazy kullanmamız bizim için iyi olacaktır.

Örnegin; sayılardan oluşan bir dizimiz olsun ve 2 ye bölünebilenleri 2 ile çarpımını hesaplamak isteyelim. Lazy kullanmadığımız durumda önce filter fonksiyonuna çalışacaktır ve daha sonra ise map fonksiyonuna çalışacaktır. Print yardımıyla fonksiyonun nasil çalıştığını görebiliyoruz.

 var numbers: [Int] = [1, 2, 3, 6, 9]
 let modifiedNumbers = numbers
     .filter { number in
         print("Even number filter")
         return number % 2 == 0
     }.map { number -> Int in
         print("Doubling the number")
         return number * 2
     }
     
 print(modifiedNumbers)
 /*
  Even number filter
  Even number filter
  Even number filter
  Even number filter
  Even number filter
  Doubling the number
  Doubling the number
  [4, 12]
  */

Bu şekilde kullanırsak beklediğimiz değer en son hesaplanacaktır. Bu durum da yapılan işi artıracak ve daha fazla bellek kullanımına ihtiyaç duyacaktır. Peki aynı örneği Lazy kullanarak yapsaydık nasıl bir sonuç elde edecektik ?

let modifiedLazyNumbers = numbers.lazy
     .filter { number in
         print("Lazy Even number filter")
         return number % 2 == 0
     }.map { number -> Int in
         print("Lazy Doubling the number")
         return number * 2
     }
     
 print(modifiedLazyNumbers)
 // Prints:
 // LazyMapSequence>, Int>(_base: Swift.LazyFilterSequence>(_base: [1, 2, 3, 6, 9], _predicate: (Function)), _transform: (Function))
 
 

İlk goze carpan nokta print kismi oluyor. Lazy oldugundan ve henuz dizideki bir degeri cagirmadigimiz icin bu sekilde gosterilmektedir. Ancak degeri istedigimizde, sadece istenilen duruma kadar ki kısım print edilecektir.

 
 print(modifiedLazyNumbers.first!)
 /*
  Prints:
  Lazy Even number filter
  Lazy Even number filter
  Lazy Doubling the number
  4
  */
  

Lazy Sequence'leri kullanirken dikkat edilmesi gereken durum talep edilene kadar fonksiyonun cağırılmasını erteler. Bu durumda sonuç değerlerini bir çıktı dizisinde saklamadığı anlamına gelmektedir ve her istek yapıldığında çağrılma işlemi tekrar tekrar yapılmaktadır. Eğer değerleri hazırda bulundurmak gerekiyorsa Lazy kullanılmamalıdır.

Sayı olarak fazla bir dizimiz varsa tum degerlerine bir islem yapmak değil de sadece koşula uyan ilk değeri hesaplamak istersek lazy kullanmak mantıklı bir durum olacaktır.


let collectionOfNumbers = (1…1000000)

let lazyFirst = collectionOfNumbers.lazy
     .filter {
         print("filter")
         return $0 % 2 == 0
     }.first
     
 print(lazyFirst) // Prints: 2

Ancak yukaridaki verilen kod orneginin daha basit bir kod ile yapilabilmektedir.


let firstWhere = collectionOfNumbers.first(where: { $0 % 2 == 0 })

print(firstWhere) // Prints: 2


How and when to use Lazy Collections in Swift
Lazy collections can increase performance if used correctly. Learn how they work, how they compute and result in increased performance.
Lazy Sequences in Swift And How They Work
Usage of high-order functions like map and filter are very common in Swift projects, as they are simple algorithms that allow you to convert extensive ideas into simple one-liners. Unfortunately, they don’t solve every issue - at least not in their default implementations.

Tags

Furkan Ozoglu

iOS Developer & Geomatics Engineer