How and when to use Lazy Collections in Swift – onlinecode
In this post we will give you information about How and when to use Lazy Collections in Swift – onlinecode. Hear we will give you detail about How and when to use Lazy Collections in Swift – onlinecodeAnd how to use it also give you demo for it if it is necessary.
Lazy collections are similar to a regular collection but change the way how modifiers like map
, filter
, and reduce
are processed. In my experience, they haven’t got as much attention as they should as they can be more performant in certain cases.
You might be more familiar with lazy vars, but have you used the lazy property on sequences before? I’ll explain to you what lazy collections are and when you should use them.
What is a lazy collection?
A lazy collection postpones calculations until they are actually needed. This can be beneficial in many different cases and prevent doing unneeded work if elements are never being asked in the end.
The following example shows a collection of numbers in which even numbers are doubled. Without using the lazy
keyword, all items would be processed directly upon creation:
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]
*/
As you can see, the doubling of the two even numbers happens after all 5 numbers are filtered.
If we would add the lazy
keyword to make the array compute modifiers lazily, the outcome would be different:
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))
In fact, the modifiers aren’t getting called at all! This is because we didn’t request any of the numbers yet. Modifiers like filter
and map
will only be executed upon requesting an element:
print(modifiedLazyNumbers.first!)
/*
Prints:
Lazy Even number filter
Lazy Even number filter
Lazy Doubling the number
4
*/
You can imagine this can save you from a lot of work if only a few items are used from a big collection.
Handling output values on the go
Another benefit of lazy collections is the option to handle output values on the go. For example, imagine having an avatar image fetcher that you want to use to fetch avatars for usernames starting with the letter A.
Without lazy it would execute as follows:
let usernames = ["Antoine", "Maaike", "Jaap", "Amber", "Lady", "Angie"]
usernames
.filter { username in
print("filtered name")
return username.lowercased().first == "a"
}.forEach { username in
print("Fetch avatar for (username)")
}
/*
Prints:
filtered name
filtered name
filtered name
filtered name
filtered name
filtered name
Fetch avatar for Antoine
Fetch avatar for Amber
Fetch avatar for Angie
*/
All names are filtered first, after which we fetch an avatar for all names starting with an A.
Although this works, we would only start fetching after the whole collection is filtered. This can be a downside if we have to iterate over a big collection of names.
Instead, if we would use a lazy collection in this scenario, we would be able to start fetching avatars on the go:
let usernames = ["Antoine", "Maaike", "Jaap", "Amber", "Lady", "Angie"]
usernames.lazy
.filter { username in
print("filtered name")
return username.lowercased().first == "a"
}.forEach { username in
print("Fetch avatar for (username)")
}
/*
Prints:
filtered name
Fetch avatar for Antoine
filtered name
filtered name
filtered name
Fetch avatar for Amber
filtered name
filtered name
Fetch avatar for Angie
*/
It’s important to understand the differences between a lazy array and a regular array. Once you know when modifiers are executed, you can decide whether or not a lazy collection makes sense for your specific case.
Use opt-in over opt-out
Now that you’ve seen that lazy collections can be more performant, you might be thinking: “I’ll just use lazy everywhere!”. However, it’s important to understand the implications of using a lazy array.
Don’t over optimize
A collection having only 5 items won’t give you a lot of performance wins when using lazy. It’s a case-per-case decision, and it also depends on the amount of work done by your modifiers. In most cases, lazy will only be useful when you’re only going to use a few items of a large collection.
On top of that, it’s important to know that lazy arrays aren’t cached.
Lazy Collections don’t cache
A lazy collection postpones executing modifiers until they’re requested. This also means that the outcome values aren’t stored in an output array. In fact, all modifiers are executed again on each item request:
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.first!)
print(modifiedLazyNumbers.first!)
/*
Prints:
Lazy Even number filter
Lazy Even number filter
Lazy Doubling the number
4
Lazy Even number filter
Lazy Even number filter
Lazy Doubling the number
4
*/
While the same scenario with a non-lazy collection would compute output values only once:
let modifiedNumbers = numbers
.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(modifiedNumbers.first!)
print(modifiedNumbers.first!)
/*
Prints:
Lazy Even number filter
Lazy Even number filter
Lazy Even number filter
Lazy Even number filter
Lazy Even number filter
Lazy Doubling the number
Lazy Doubling the number
4
4
*/
Take the delay into account
A lazy collection only performs its modifiers upon request. In case one of the modifiers performs tasks that can take time, you might want to step away from using lazy.
In other words, it might be beneficial to calculate output values upfront and have them ready when they’re actually needed. You don’t want to perform the heavy lifting while the user is scrolling, for example.
Consider using standard Swift APIs over lazy arrays
A topic on its own and another reason to reconsider using lazy collections. Swift provides us a whole API of optimized modifiers to work with collections that might be a better solution to your problem.
For example, you might think it’s a smart decision to use lazy in this scenario as it prevents us from filter all numbers before we start using only the first element:
let collectionOfNumbers = (1…1000000)
let lazyFirst = collectionOfNumbers.lazy
.filter {
print("filter")
return $0 % 2 == 0
}.first
print(lazyFirst) // Prints: 2
However, in this case, we benefit from using first(where:)
instead. It’s a standard Swift API and it allows us to benefit from all underlying (future) optimizations:
let firstWhere = collectionOfNumbers.first(where: { $0 % 2 == 0 })
print(firstWhere) // Prints: 2
I wrote a whole blog post about these decisions which you can read: Performance, functional programming and collections in Swift.
Conclusion
Lazy collections are a powerful element of Swift and can result in better performance for specific cases. It’s important to know its implications to decide whether or not lazy arrays are the right solution for your scenario.
If you like to improve your Swift knowledge, even more, check out the Swift category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.
Thanks!
<!– Disable cross link to Medium
Also published on Medium.
–>
Hope this code and post will helped you for implement How and when to use Lazy Collections in Swift – onlinecode. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs