I am attempting to add an extension to the Array type in Swift limited to Arrays whose elements conform to the equatable protocol. I am attempting to define a function in the following manner:
import Foundation
extension Array where Iterator.Element: Equatable {
func deletedIndicies<T: Equatable>(newArray: [T]) -> [Int] {
var indicies = [Int]()
for element in self {
if newArray.index(of: element) == nil {
indicies.append(self.index(of: element)!)
}
}
return indicies
}
}
}
The purpose of the function is to return the indices of any items in the original array that do not appear in the newArray
.
The error I receive in Xcode is: Cannot invoke 'index' with an argument list of type '(of: Element)'
Since I am defining the function for only Arrays whose elements are equatable and am requiring that the elements of the newArray
are equatable, I am unsure why I cannot invoke the index method.
The problem is you're defining a new generic placeholder T
in your method – which is not necessarily the same type as Element
. Therefore when you say newArray.index(of: element)
, you're trying to pass an Element
into a argument of type T
.
The solution therefore is to simply to type the newArray:
parameter as [Element]
:
extension Array where Element : Equatable {
func deletedIndicies(byKeeping elementsToKeep: [Element]) -> [Int] {
// ...
}
}
As a side note, this method could also be implemented as:
extension Array where Element : Equatable {
func deletedIndicies(byKeeping elementsToKeep: [Element]) -> [Int] {
// use flatMap(_:) to iterate over a sequence of pairs of elements with indices,
// returning the index of the element, if elementsToKeep doesn't contains it,
// or nil otherwise, in which case flatMap(_:) will filter it out.
return self.enumerated().flatMap {
elementsToKeep.contains($1) ? nil : $0
}
}
}
Also, if you change the constraint on Element
to Hashable
, this could be also be implemented in O(n), rather than O(n * m) time, which could potentially be desirable:
extension Array where Element : Hashable {
func deletedIndicies(byKeeping elementsToKeep: [Element]) -> [Int] {
// create new set of elements to keep.
let setOfElementsToKeep = Set(elementsToKeep)
return self.enumerated().flatMap {
setOfElementsToKeep.contains($1) ? nil : $0
}
}
}
来源:https://stackoverflow.com/questions/41045212/swift-extension-of-array-with-equatable-elements-cannot-call-indexof