extension Array {
func removeObject<T where T : Equatable>(object: T) {
var index = find(self, object)
self.removeAtIndex(index)
}
}
但是,我在var index = find(self, object)
&#39; T&#39;不可转换为&#39; <&#39;
我也试过这个方法签名:func removeObject(object: AnyObject)
但是,我得到了同样的错误:
&#39; AnyObject&#39;不可转换为&#39; <&#39;
这样做的正确方法是什么?
答案 0 :(得分:165)
从 Swift 2 开始,可以使用协议扩展方法来实现。
removeObject()
被定义为符合所有类型的方法
到RangeReplaceableCollectionType
(特别是Array
)if
该集合的元素是Equatable
:
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注意到
在注释中,现在实际上可以在对模板更具限制性的泛型类型上编写方法,因此该方法
现在实际上可以定义为Array
的扩展名:
extension Array where Element : Equatable {
// ... same method as above ...
}
协议扩展仍具有适用的优点 一组更大的类型。
更新 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)
}
}
}
答案 1 :(得分:65)
您无法在对模板具有更高限制性的泛型类型上编写方法。
注意:从Swift 2.0开始,您现在可以在模板上编写 更严格的方法。如果您已将代码升级到2.0,请进一步查看其他答案,以了解使用扩展程序实现此目的的新选项。
您收到错误'T' is not convertible to 'T'
的原因是您实际上在方法中定义了一个与原始T无关的 new T.如果您想使用T在您的方法中,您可以在不指定方法的情况下执行此操作。
您得到第二个错误'AnyObject' is not convertible to 'T'
的原因是T的所有可能值都不是所有类。对于要转换为AnyObject的实例,它必须是一个类(它不能是结构,枚举等)。
最好的办法是让它成为一个接受数组作为参数的函数:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}
或者不是修改原始数组,而是通过返回副本使您的方法更安全,可重复使用:
func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}
作为我不推荐的替代方法,如果无法将存储在数组中的类型转换为方法模板(即相等),则可以使方法无提示失败。 (为清楚起见,我使用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
答案 2 :(得分:28)
简明扼要地说:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T])
{
var index = find(array, object)
array.removeAtIndex(index!)
}
答案 3 :(得分:17)
阅读完上述所有内容后,我认为最好的答案是:
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。以下是一个扩展,提供详尽,快速,变异和创建变体。
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"]
答案 4 :(得分:13)
使用协议扩展,您可以执行此操作,
extension Array where Element: Equatable {
mutating func remove(object: Element) {
if let index = indexOf({ $0 == object }) {
removeAtIndex(index)
}
}
}
类的相同功能,
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,它就会变得模棱两可,编译器会抛出一个错误。
答案 5 :(得分:7)
在swift 2.0中使用协议扩展
drop: function (event, ui) {
$(this).droppable('disable');
}
答案 6 :(得分:4)
如何使用过滤?即使使用[AnyObject],以下内容也能很好地工作。
import Foundation
extension Array {
mutating func removeObject<T where T : Equatable>(obj: T) {
self = self.filter({$0 as? T != obj})
}
}
答案 7 :(得分:2)
还有一种可能性从数组中删除项目而不会出现不安全的使用,因为要删除的对象的泛型类型不能与数组的类型相同。使用选项也不是完美的方式,因为它们非常慢。因此,您可以使用类似于在排序数组时使用的闭包。
//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
来缩短函数调用,然后将if-evaluation替换为equality(item)
,并通过array.removeFirst({ $0 == "Banana" })
调用函数。
答案 8 :(得分:2)
无需扩展:
var ra = [7, 2, 5, 5, 4, 5, 3, 4, 2]
print(ra) // [7, 2, 5, 5, 4, 5, 3, 4, 2]
ra.removeAll(where: { $0 == 5 })
print(ra) // [7, 2, 4, 3, 4, 2]
if let i = ra.firstIndex(of: 4) {
ra.remove(at: i)
}
print(ra) // [7, 2, 3, 4, 2]
if let j = ra.lastIndex(of: 2) {
ra.remove(at: j)
}
print(ra) // [7, 2, 3, 4]
答案 9 :(得分:1)
使用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
}
}
}
}
答案 10 :(得分:1)
也许我不明白这个问题。
为什么这个行不通?
import Foundation
extension Array where Element: Equatable {
mutating func removeObject(object: Element) {
if let index = self.firstIndex(of: object) {
self.remove(at: index)
}
}
}
var testArray = [1,2,3,4,5,6,7,8,9,0]
testArray.removeObject(object: 6)
let newArray = testArray
var testArray2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
testArray2.removeObject(object: "6")
let newArray2 = testArray2
答案 11 :(得分:0)
我最终得到了以下代码。
extension Array where Element: Equatable {
mutating func remove<Element: Equatable>(item: Element) -> Array {
self = self.filter { $0 as? Element != item }
return self
}
}
答案 12 :(得分:0)
我设法通过在for循环之外实现计数来从数组[String:AnyObject]
中移除[[String:AnyObject]]
,以表示自.find
和.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
}
答案 13 :(得分:-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
}
}
}
答案 14 :(得分:-4)
我能够使用它:
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!)
}
}
}