问题描述
试图编写一个通用数组扩展,它可以获得所有不等于值的项的索引。示例
let arr:[String] = [Empty,Empty,Full空,全]
让结果:[Int] = arr.indexes(ofItemsNotEqualTo item:Empty)
//返回[2,4]
$ c $
<$ c $
我尝试了一个通用函数: c>扩展数组{
func索引< T:可比较>(ofItemsNotEqualTo item:T) - > [INT]? {
var result:[Int] = []
for self.enumerated(){
if elem!= item {
result.append(n )
}
}
返回result.isEmpty? nil:result
}
}
但是这给出了一个警告:二元运算符不能应用于元素和T类型的操作数。
所以我做了这个我投的元素(注意
扩展数组{
func索引< T:可等分>(ofItemsNotEqualTo item:T) - > [INT]? {
var result:[Int] = [] $ b $ for(n,elem)in self.enumerated(){
if elem as? T!= item {
result.append(n)
}
}
return result.isEmpty? nil:result
}
}
但是现在看起来类型检查有出去了窗口,因为如果我传入一个整数,我得到了错误的结果
let arr:[String] = [
让结果:[Int] = arr.indexes(ofItemsNotEqualTo item:100)
//返回[0,1 ,2,3,4]
帮助将不胜感激。
使用 reduce 函数有更好的方法吗?
解决方案您已经定义了一个泛型方法
func索引< T:Equatable>(ofItemsNotEqualTo item :T)→> [INT]?
它的参数类型为 T which必须是
Equatable ,但与数组的 Element 类型无关。
因此
let arr = [Empty,Empty,完整,空白,全部]
let result = arr.indexes(ofItemsNotEqualTo:100)
编译,但 elem as? T 对所有数组给出 nil (这是!= item )
元素。
你想要的是一种仅为
Equatable 元素数组定义的方法。这可以通过限制的
扩展来实现:
扩展数组其中元素:Equatable {
func索引(ofItemsNotEqualTo item:Element) - > [INT]? {
var result:[Int] = [] $ b $ for(n,elem)in enumerated(){
if elem!= item {
result.append(n)
}
}
返回result.isEmpty? nil:result
}
}
其实我不会让返回值可选。
如果所有元素都等于给定项目,那么逻辑
返回值就是空数组。 >有没有更好的方法来使用reduce函数做到这一点?
好的,你可以 使用 reduce(),但这不是非常有效,因为在每个迭代步骤中都会创建中间数组:
扩展数组其中元素:Equatable {
func索引(ofItemsNotEqualTo item:Element) - > [Int] {
return enumerated()。reduce([]){
$ 1.element == item? $ 0:$ 0 + [$ 1.offset]
}
}
}
你实际上有一个
filter + map操作:
扩展数组其中Element:Equatable {
func索引(ofItemsNotEqualTo item:Element) - > [Int] {
return enumerated()。filter {$ 0.element!= item} .map {$ 0.offset}
}
}
可以使用 flatMap()简化:
扩展数组其中,Element:Equatable {
func索引(ofItemsNotEqualTo item:Element) - > [Int] {
return enumerated()。flatMap {$ 0.element!= item? $ 0.offset:nil}
}
}
示例:
let arr = [Empty,Empty,Full,Empty,Full]
arr .indexes(ofItemsNotEqualTo:Full)// [0,1,3]
[1,1,1] .indexes(ofItemsNotEqualTo:1)// []
arr.indexes(ofItemsNotEqualTo:100)
//错误:无法将'Int'类型的值转换为期望的参数类型'String'
Swift 3
Trying to write a generic array extension that gets all indexes of items that DON'T equal value
example
let arr: [String] = ["Empty", "Empty", "Full", "Empty", "Full"] let result: [Int] = arr.indexes(ofItemsNotEqualTo item: "Empty") //returns [2, 4]I tried to make a generic function:
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 } }But that gives a warning: Binary operator cannot be applied to operands of type "Element" and "T".
So then I did this where I cast the element (note the as?)
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 } }But now it seems the type checking has gone out the window, because if I pass in an integer I get the wrong result
let arr: [String] = ["Empty", "Empty", "Full", "Empty", "Full"] let result: [Int] = arr.indexes(ofItemsNotEqualTo item: 100) //returns [0, 1, 2, 3, 4]Help would be greatly appreciated.
Is there a better way to do this with the reduce function?
解决方案You have defined a generic method
func indexes<T: Equatable>(ofItemsNotEqualTo item: T) -> [Int]?which takes an argument of type T which is required to beEquatable, but is unrelated to the Element type of the array.
Therefore
let arr = ["Empty", "Empty", "Full", "Empty", "Full"] let result = arr.indexes(ofItemsNotEqualTo: 100)compiles, but elem as? T gives nil (which is != item)for all array elements.
What you want is a method which is defined only for arrays ofEquatable elements. This can be achieved with a constrainedextension:
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 } }Actually I would not make the return value an optional.If all elements are equal to the given item, then the logicalreturn value would be the empty array.
Well, you could use reduce(), but that is not very efficient because intermediate arrays are created in each iteration step:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().reduce([]) { $1.element == item ? $0 : $0 + [$1.offset] } } }What you actually have is a"filter + map" operation:
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().filter { $0.element != item }.map { $0.offset } } }which can be simplified using flatMap():
extension Array where Element: Equatable { func indexes(ofItemsNotEqualTo item: Element) -> [Int] { return enumerated().flatMap { $0.element != item ? $0.offset : nil } } }Examples:
let arr = ["Empty", "Empty", "Full", "Empty", "Full"] arr.indexes(ofItemsNotEqualTo: "Full") // [0, 1, 3] [1, 1, 1].indexes(ofItemsNotEqualTo: 1) // [] arr.indexes(ofItemsNotEqualTo: 100) // error: cannot convert value of type 'Int' to expected argument type 'String'
这篇关于Swift通用数组函数查找元素的所有索引都不匹配项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!