Search code examples
swiftgenericsswift-extensions

Generic Extension to Array Not Working


I've been playing around with Generics and Extensions to existing types in Swift 3. I wrote two generic Array functions that extends Array with find-and-replace methods, named replaced() and replace(). The replaced() function works as intended but the replace() function has a compile time error. Here is the code and a test of one of the methods.

extension Array {
    func replaced<T: Equatable>(each valueToReplace: T, with newValue: T) -> [T] {
        var newArray:[T] = []
        for index:Int in 0..<self.count {
            if let temp = self[index] as? T, temp == valueToReplace{
                newArray.append(newValue)
            }else{
                newArray.append(self[index] as! T)
            }
        }
        return newArray
    }
    mutating func replace<T: Equatable>(each valueToReplace: T, with newValue: T) {
        for index:Int in 0..<self.count {
            if let temp = self[index] as? T, temp == valueToReplace {
                // FIXME: self[index] = newValue 
            }
        }
        return
    }
}
var j = [1,2,3,4,3,6,3,8,9]
var newArray = j.replaced(each: 3, with: 0)

I get a compile time error on the second method, replace(), at the line commented out with "//FIXME:" annotation. The compile time error says, "Ambiguous reference to member 'subscript'".

How can I fix the replace() code so it works?


Solution

  • Give this a shot

    extension Array where Element: Equatable {
        func replaced (each valueToReplace: Element, with newValue: Element) -> [Element] {
            var newArray = [Element]()
            newArray.reserveCapacity(self.count)
    
            for element in self {
                let newElement = (element == valueToReplace) ? newValue : element
                newArray.append(newElement) 
            }
    
            return newArray
        }
    
        mutating func replace(each valueToReplace: Element, with newValue: Element) {
            for (i, element) in self.enumerated() {
                if element == valueToReplace { self[i] = newValue }
            }
        }
    }
    
    var j = [1,2,3,4,3,6,3,8,9]
    var newArray = j.replaced(each: 3, with: 0)
    

    It would be better to remove the redundancy by just making replaced delegate to replace:

    extension Array where Element: Equatable {
        func replaced(each valueToReplace: Element, with newValue: Element) -> [Element] {
            var copy = self
            copy.replace(each: valueToReplace, with: newValue)
            return copy
        }
    
        mutating func replace(each valueToReplace: Element, with newValue: Element) {
            for (i, element) in self.enumerated() {
                if element == valueToReplace { self[i] = newValue }
            }
        }
    }