数组扩展名,用于按值删除对象
extension Array { func removeObject<T where T : Equatable>(object: T) { var index = find(self, object) self.removeAtIndex(index) } }
但是,我得到一个错误var index = find(self, object)
'T'不能转换为'T'
我也试过用这个方法签名: func removeObject(object: AnyObject)
,但是,我得到了同样的错误:
“AnyObject”不能转换为“T”
什么是正确的方法来做到这一点?
从Swift 2开始 ,这可以通过协议扩展方法来实现。 如果集合的元素是可Equatable
removeObject()
被定义为符合RangeReplaceableCollectionType
(特别是在Array
)的所有types的方法:
extension RangeReplaceableCollectionType where Generator.Element : Equatable { // Remove first collection element that is equal to the given `object`: mutating func removeObject(object : Generator.Element) { if let index = self.indexOf(object) { self.removeAtIndex(index) } } }
例:
var ar = [1, 2, 3, 2] ar.removeObject(2) print(ar) // [1, 3, 2]
Swift 2 / Xcode 7 beta 2的更新:在注释中注意到Airspeed Velocity,现在实际上可以在generics上编写一个对模板更加严格的方法,所以现在这个方法实际上可以定义为扩展Array
:
extension Array where Element : Equatable { // ... same method as above ... }
协议扩展仍然具有适用于更大types的优点。
Swift 3的更新:
extension Array where Element: Equatable { // Remove first collection element that is equal to the given `object`: mutating func remove(object: Element) { if let index = index(of: object) { remove(at: index) } } }
您不能在模板上对限制性更强的genericstypes编写方法。
注意 :从Swift 2.0开始,现在可以编写对模板更严格的方法。 如果您已将代码升级到2.0,请参阅其他答案,以获取使用扩展实现此选项的新选项。
你得到错误'T' is not convertible to 'T'
的原因'T' is not convertible to 'T'
是,你实际上在你的方法中定义了一个新的 T,与原来的T无关。如果你想在你的方法中使用T,可以这样做,而不用在你的方法中指定它。
你得到第二个错误'AnyObject' is not convertible to 'T'
是'AnyObject' is not convertible to 'T'
所有可能的值不是所有的类。 对于要转换为AnyObject的实例,它必须是一个类(它不能是一个结构,枚举等)。
你最好的select是把它作为一个接受数组作为参数的函数:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) { }
或者不是修改原始数组,而是通过返回一个副本使您的方法更安全,更可重用:
func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] { }
作为我不build议的替代方法,如果存储在数组中的types无法转换为方法模板(可以是equatable),则可以使方法失败。 (为了清楚起见,我使用U而不是T来表示方法的模板):
extension Array { mutating func removeObject<U: Equatable>(object: U) { var index: Int? for (idx, objectToCompare) in enumerate(self) { if let to = objectToCompare as? U { if object == to { index = idx } } } if(index != nil) { self.removeAtIndex(index!) } } } var list = [1,2,3] list.removeObject(2) // Successfully removes 2 because types matched list.removeObject("3") // fails silently to remove anything because the types don't match list // [1, 3]
编辑为了克服沉默失败,你可以作为一个布尔返回成功:
extension Array { mutating func removeObject<U: Equatable>(object: U) -> Bool { for (idx, objectToCompare) in self.enumerate() { //in old swift use enumerate(self) if let to = objectToCompare as? U { if object == to { self.removeAtIndex(idx) return true } } } return false } } var list = [1,2,3,2] list.removeObject(2) list list.removeObject(2) list
简要而简洁地说:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) { var index = find(array, object) array.removeAtIndex(index!) }
看完以上所有内容,我的脑海中最好的答案是:
func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] { return fromArray.filter { return $0 != object } }
样品:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"] myArray = arrayRemovingObject("Cat", fromArray:myArray )
Swift 2(xcode 7b4)数组扩展:
extension Array where Element: Equatable { func arrayRemovingObject(object: Element) -> [Element] { return filter { $0 != object } } }
样品:
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"] myArray = myArray.arrayRemovingObject("Cat" )
Swift 3.1更新
现在回到这个Swift 3.1已经出来了。 下面是一个扩展,提供详尽,快速,变异和创build变种。
extension Array where Element:Equatable { public mutating func remove(_ item:Element ) { var index = 0 while index < self.count { if self[index] == item { self.remove(at: index) } else { index += 1 } } } public func array( removing item:Element ) -> [Element] { var result = self result.remove( item ) return result } }
样品:
// Mutation... var array1 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"] array1.remove("Cat") print(array1) // ["Dog", "Turtle", "Socks"] // Creation... let array2 = ["Cat", "Dog", "Turtle", "Cat", "Fish", "Cat"] let array3 = array2.array(removing:"Cat") print(array3) // ["Dog", "Turtle", "Fish"]
有了协议扩展,你可以做到这一点,
extension Array where Element: Equatable { mutating func remove(object: Element) { if let index = indexOf({ $0 == object }) { removeAtIndex(index) } } }
类的function相同,
Swift 2
extension Array where Element: AnyObject { mutating func remove(object: Element) { if let index = indexOf({ $0 === object }) { removeAtIndex(index) } } }
Swift 3
extension Array where Element: AnyObject { mutating func remove(object: Element) { if let index = index(where: { $0 === object }) { remove(at: index) } } }
但是如果一个类实现了Equatable,它会变得不明确,编译器会给出一个错误。
在swift 2.0中使用协议扩展
extension _ArrayType where Generator.Element : Equatable{ mutating func removeObject(object : Self.Generator.Element) { while let index = self.indexOf(object){ self.removeAtIndex(index) } } }
什么使用过滤? 即使使用[AnyObject],以下工作也相当顺利。
import Foundation extension Array { mutating func removeObject<T where T : Equatable>(obj: T) { self = self.filter({$0 as? T != obj}) } }
还有另外一种可能性,即从一个数组中删除一个项目,而不会有不安全的使用,因为要删除的对象的genericstypes不能和数组types相同。 使用可选项也不是完美的方式,因为它们很慢。 因此,您可以使用一个闭包,就像它在sorting数组时已经使用的那样。
//removes the first item that is equal to the specified element mutating func removeFirst(element: Element, equality: (Element, Element) -> Bool) -> Bool { for (index, item) in enumerate(self) { if equality(item, element) { self.removeAtIndex(index) return true } } return false }
当用这个函数扩展Array
类时,可以通过执行以下操作来删除元素:
var array = ["Apple", "Banana", "Strawberry"] array.removeFirst("Banana") { $0 == $1 } //Banana is now removed
但是,你甚至可以删除一个元素,只要它具有相同的内存地址(当然,只适用于符合AnyObject
协议的类):
let date1 = NSDate() let date2 = NSDate() var array = [date1, date2] array.removeFirst(NSDate()) { $0 === $1 } //won't do anything array.removeFirst(date1) { $0 === $1 } //array now contains only 'date2'
好的是,你可以指定要比较的参数。 例如,当你有一个数组的数组时,你可以指定相等的闭包为{ $0.count == $1.count }
,第一个数组的大小和要移除的大小相同。
你甚至可以通过调用mutating func removeFirst(equality: (Element) -> Bool) -> Bool
代替函数调用,然后用equality(item)
replacemutating func removeFirst(equality: (Element) -> Bool) -> Bool
评估,并通过array.removeFirst({ $0 == "Banana" })
。
使用indexOf
而不是for
或enumerate
:
extension Array where Element: Equatable { mutating func removeElement(element: Element) -> Element? { if let index = indexOf(element) { return removeAtIndex(index) } return nil } mutating func removeAllOccurrencesOfElement(element: Element) -> Int { var occurrences = 0 while true { if let index = indexOf(element) { removeAtIndex(index) occurrences++ } else { return occurrences } } } }
我终于结束了以下代码。
extension Array where Element: Equatable { mutating func remove<Element: Equatable>(item: Element) -> Array { self = self.filter { $0 as? Element != item } return self } }
由于.find
和.filter
与[String:AnyObject]
不兼容,我通过在for循环之外实现一个计数来表示索引, .find
从数组[[String:AnyObject]]
.filter
[String:AnyObject]
。
let additionValue = productHarvestChoices[trueIndex]["name"] as! String var count = 0 for productHarvestChoice in productHarvestChoices { if productHarvestChoice["name"] as! String == additionValue { productHarvestChoices.removeAtIndex(count) } count = count + 1 }
在Swift 2中的实现:
extension Array { mutating func removeObject<T: Equatable>(object: T) -> Bool { var index: Int? for (idx, objectToCompare) in self.enumerate() { if let toCompare = objectToCompare as? T { if toCompare == object { index = idx break } } } if(index != nil) { self.removeAtIndex(index!) return true } else { return false } } }
我能够得到它的工作:
extension Array { mutating func removeObject<T: Equatable>(object: T) { var index: Int? for (idx, objectToCompare) in enumerate(self) { let to = objectToCompare as T if object == to { index = idx } } if(index) { self.removeAtIndex(index!) } } }