Suppose I have the following
let ids = mySet.lazy.map { $0.id }
ids.contains(...)
Does the .contains()
function make lazy
redundant? I'm assuming it has to perform map
on the whole of mySet
to be able to perform contains()
?
Or am I wrong?
CodePudding user response:
You are wrong.
Adding .lazy
causes map to return a LazyMapSequence
instead of an Array
. When you call .contains
on this LazyMapSequence
, it will execute the mapping operation on each element as .contains
checks it.
Imagine your set has 100 items. .contains
quits as soon as it finds the item you are searching for, so if you get lucky and the first item in your Set
satisfies .contains
, then only that item will be .map
ped and .contains
will immediately return true
.
Note that Set
s are unordered, so the order it is searched is unspecified.
Try this in a Playground:
struct Person : Hashable {
var id: Int
var name: String
}
let mySet = Set([Person(id: 1, name: "Joe"),
Person(id: 2, name: "Abhijit"),
Person(id: 3, name: "Fred")])
let ids = mySet.lazy.map { (person) -> Int in print("mapped \(person)"); return person.id }
print(ids.contains(1))
Observe the output. When I tried it I got:
mapped Person(id: 1, name: "Joe") true
Then remove .lazy
and run it again. I got:
mapped Person(id: 1, name: "Joe") mapped Person(id: 3, name: "Fred") mapped Person(id: 2, name: "Abhijit") true
So .lazy
eliminates the need to run .map
on every item. If .contains
finds what it is looking for, then it is unnecessary to run .map
on every item.
Note: If the Set
does not contain the item you are searching for, then every item will be visited and .map
ped before .contains
can return false
.
Now what if contains is called multiple times? Will that have to start from an “unmapped” sequence again? Or will it have stored the previously mapped values somewhere?
The second effect of lazy
is that no storage is used to hold the intermediate mapped values. So calling contains
multiple times will execute the mapping operation again for each set value that is accessed.