Hello. Often I need update each element in collections. And I wrote next function
public protocol Adjust {
mutating func preAnimationAdjust()
}
func adjustEachElementInCollection<C: MutableCollection>(c: inout C) where C.Element: Adjust {
for index in c.indices {
var item = c[index]
item.preAnimationAdjust()
c[index] = item
}
}
And next test gives away a correct result
struct Bee: PreAnimationAdjust {
var name: String
mutating func preAnimationAdjust() {
name += "A"
}
}
public func test() {
var bees = [Bee(name: "Anna"), Bee(name: "Anton"), Bee(name: "Kit")]
print(bees) // [Bee(name: "Anna"), Bee(name: "Anton"), Bee(name: "Kit")]
adjustEachElementInCollection(c: &bees)
print(bees) //[Bee(name: "AnnaA"), Bee(name: "AntonA"), Bee(name: "KitA")]
}
Is it safe approach to mutation a collection? In final I need same type of a collection after mutation, therefore the .map does not fit.
Nevin
2
This is not quite right. It will work, but it can run into a performance cliff if the collection’s Indices type retains the collection itself (as, for example, Dictionary.Values.Indices does).
In general, you should not use the indices property for mutation. Instead, manually advance an index. This is mentioned in the documentation of indices.
Here’s a method that lets you write in-place transformations of a collection:
extension MutableCollection {
mutating func transform(_ transform: (inout Element) throws -> Void) rethrows {
var i = startIndex
while i != endIndex {
try transform(&self[i])
formIndex(after: &i)
}
}
}
Usage:
myNumbers.transform{ $0 += 1 }
2 Likes
Wow, it is very smart closure usage