斯威夫特3
例
let arr: [String] = ["Empty","Empty","Full","Full"] let result: [Int] = arr.indexes(ofItemsNotEqualTo item: "Empty") //returns [2,4]
extension Array { func indexes<T: Equatable>(ofItemsNotEqualTo item: T) -> [Int]? { var result: [Int] = [] for (n,elem) in self.enumerated() { if elem != item { result.append(n) } } return result.isEmpty ? nil : result } }
但是这会发出警告:二进制运算符不能应用于“Element”和“T”类型的操作数.
所以我在这里投了元素(注意为?)
extension Array { func indexes<T: Equatable>(ofItemsNotEqualTo item: T) -> [Int]? { var result: [Int] = [] for (n,elem) in self.enumerated() { if elem as? T != item { result.append(n) } } return result.isEmpty ? nil : result } }
但现在似乎类型检查已经消失了,因为如果我传入一个整数,我得到错误的结果
let arr: [String] = ["Empty","Full"] let result: [Int] = arr.indexes(ofItemsNotEqualTo item: 100) //returns [0,1,2,3,4]
非常感谢帮助.
解决方法
您已经定义了一个通用方法
func indexes<T: Equatable>(ofItemsNotEqualTo item: T) -> [Int]?
它采用类型为T的参数
Equatable,但与数组的Element类型无关.
因此
let arr = ["Empty","Full"] let result = arr.indexes(ofItemsNotEqualTo: 100)
编译,但是作为? T给出nil(这是!=项目)
对于所有数组元素.
你想要的是一个只为数组定义的方法
等同的元素.这可以通过约束来实现
延期:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int]? { var result: [Int] = [] for (n,elem) in enumerated() { if elem != item { result.append(n) } } return result.isEmpty ? nil : result } }
实际上我不会将返回值设为可选.
如果所有元素都等于给定项,那么逻辑
返回值将是空数组.
Is there a better way to do this with the reduce function?
好吧,您可以使用reduce(),但这不是非常有效,因为在每个迭代步骤中都会创建中间数组:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().reduce([]) { $1.element == item ? $0 : $0 + [$1.offset] } } }
你实际拥有的是一个
“过滤地图”操作:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().filter { $0.element != item }.map { $0.offset } } }
可以使用flatMap()简化:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().flatMap { $0.element != item ? $0.offset : nil } } }
例子:
let arr = ["Empty","Full"] arr.indexes(ofItemsNotEqualTo: "Full") // [0,3] [1,1].indexes(ofItemsNotEqualTo: 1) // [] arr.indexes(ofItemsNotEqualTo: 100) // error: cannot convert value of type 'Int' to expected argument type 'String'