Answers:
从Swift 2开始,这可以通过协议扩展方法来实现。
如果集合的元素为:,则将其removeObject()
定义为符合RangeReplaceableCollectionType
(特别是Array
)所有类型的方法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]
更新斯威夫特2 / Xcode的7测试版2:空速速度在评论中发现,现在其实可以写一个通用的类型,它是在模板更严格的方法,因此该方法可现在居然被定义为一个扩展的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)
}
}
}
remove(object: Element)
为了符合Swift API设计指南并避免冗长,我将其声明重命名为。我已经提交了反映此内容的编辑。
您不能以对模板有更多限制的通用类型编写方法。
注:如雨燕2.0的,现在就可以编写方法是在模板上更加严格。如果您已将代码升级到2.0,请进一步查看其他答案,以获取新的选项来使用扩展来实现此目的。
出现错误的原因'T' is not convertible to 'T'
是,您实际上在方法中定义了一个与原始T根本不相关的新 T。如果要在方法中使用T,则无需在方法上指定它即可。
您收到第二个错误的原因'AnyObject' is not convertible to 'T'
是T的所有可能值都不是所有类。要将实例转换为AnyObject,它必须是一个类(不能是struct,enum等)。
最好的选择是使它成为接受数组作为参数的函数:
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
find
方法?
Equatable
协议的任何对象。UIView这样做是的,它将可以与
enumerate(self)
必须修复self.enumerate()
简明扼要:
func removeObject<T : Equatable>(object: T, inout fromArray array: [T])
{
var index = find(array, object)
array.removeAtIndex(index!)
}
inout
。我认为即使inout
完整无缺,也可以使用array = array.filter() { $0 != object }
。
阅读以上所有内容后,我认为最好的答案是:
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"]
filter
函数已经为您处理该功能时,我倾向于同意该函数样式。这似乎是重复的功能。不过,这是一个不错的答案:]
使用协议扩展,您可以执行此操作,
extension Array where Element: Equatable {
mutating func remove(object: Element) {
if let index = indexOf({ $0 == object }) {
removeAtIndex(index)
}
}
}
类的功能相同,
迅捷2
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = indexOf({ $0 === object }) {
removeAtIndex(index)
}
}
}
迅捷3
extension Array where Element: AnyObject {
mutating func remove(object: Element) {
if let index = index(where: { $0 === object }) {
remove(at: index)
}
}
}
但是,如果一个类实现了Equatable,它将变得模棱两可,并且编译器将引发错误。
Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
还有一种可能会从数组中删除一项而没有不安全使用的可能性,因为要删除的对象的通用类型不能与数组的类型相同。使用可选选项也不是理想的选择,因为它们非常慢。因此,您可以使用闭包,例如在对数组进行排序时已经使用的闭包。
//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" })
。
==
是一个函数,因此您也可以为实现的任何类型==
(例如String,Int等)这样调用它:array.removeFirst("Banana", equality:==)
无需扩展:
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]
使用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
}
}
}
}
也许我不明白这个问题。
为什么不起作用?
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
我通过在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
}
在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
}
}
}
T where
从您的方法声明中删除。所以就这样func removeObject<T: Equatable>
。这个问题是相关的:stackoverflow.com/questions/24091046/...