jkmassel
(Jeremy Massel)
1
Often, when enumerating a collection without a need to map or filter, I'll reach for forEach. However this doesn't work when I'm interested in seeing the index of a particular element, requiring me to drop down to the slightly less terse, and much less Swifty:
for (ix, element) in foo.enumerated(){
doStuff(ix, element)
}
when what I really want is:
foo.forEachWithIndex(doStuff)
The following extension allows this, and seems to be a simple, non-breaking change to the standard library, if accepted:
extension Array{
func forEachWithIndex(_ callback: (Int, Element) -> ()){
for (index, element) in self.enumerated(){
callback(index, element)
}
}
}
Thanks for reading!
Don't think there's a need to extend the name that much, func forEach(_ body: (Int, Self.Element) throws -> Void) rethrows in pair with the non-enumerated forEach is just fine.
P.S. It would be Sequence we are adding to.
jrose
(Jordan Rose)
3
foo.enumerated().forEach is 90% of that without adding a new function (you have to unpack the elements inside the closure). How often does this come up in practice?
4 Likes
Instead of foo.enumerated() you might want to use:
-
zip(0..., foo) or
zip(foo.indices, foo)
See also:
1 Like
Ben_Cohen
(Ben Cohen)
5
It's also worth noting that often when you need to iterate over indices (rather than just elements) its because you plan on mutating the array using that index. But a higher-level function like this will be holding a copy of the collection while looping, which means for value types a full copy will be triggered on first mutation. The more layers of abstraction/convenience in an operation like this, the more likely the user will miss this issue (which is easily missed, I did just the other day).
4 Likes