ios 按值删除对象的数组扩展

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24938948/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:32:24  来源:igfitidea点击:

Array extension to remove object by value

iosarraysswift

提问by Snowman

extension Array {
    func removeObject<T where T : Equatable>(object: T) {
        var index = find(self, object)
        self.removeAtIndex(index)
    }
}

However, I get an error on var index = find(self, object)

但是,我收到一个错误 var index = find(self, object)

'T' is not convertible to 'T'

'T' 不可转换为 'T'

I also tried with this method signature: func removeObject(object: AnyObject), however, I get the same error:

我也试过这个方法签名:func removeObject(object: AnyObject)但是,我得到了同样的错误:

'AnyObject' is not convertible to 'T'

“AnyObject”不可转换为“T”

What is the proper way to do this?

这样做的正确方法是什么?

回答by Martin R

As of Swift 2, this can be achieved with a protocol extension method. removeObject()is defined as a method on all types conforming to RangeReplaceableCollectionType(in particular on Array) if the elements of the collection are Equatable:

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)
        }
    }
}

Example:

例子:

var ar = [1, 2, 3, 2]
ar.removeObject(2)
print(ar) // [1, 3, 2]

Update for Swift 2 / Xcode 7 beta 2:As Airspeed Velocity noticed in the comments, it is now actually possible to write a method on a generic type that is more restrictive on the template, so the method could now actually be defined as an extension of Array:

更新斯威夫特2 / Xcode的7测试版2:空速速度在评论中发现,现在其实可以写一个通用的类型,它是在模板更严格的方法,因此该方法可现在居然被定义为一个扩展的Array

extension Array where Element : Equatable {

    // ... same method as above ...
}

The protocol extension still has the advantage of being applicable to a larger set of types.

协议扩展仍然具有适用于更大类型集的优势。

Update for Swift 3:

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)
        }
    }
}

回答by drewag

You cannot write a method on a generic type that is more restrictive on the template.

您不能在对模板有更多限制的泛型类型上编写方法。

NOTE: as of Swift 2.0, you can now write methods that aremore restrictive on the template. If you have upgraded your code to 2.0, see other answers further down for new options to implement this using extensions.

注意:从 Swift 2.0 开始,您现在可以编写对模板更多限制的方法。如果您已将代码升级到 2.0,请进一步查看其他答案以了解使用扩展实现此功能的新选项。

The reason you get the error 'T' is not convertible to 'T'is that you are actually defining a newT in your method that is not related at all to the original T. If you wanted to use T in your method, you can do so without specifying it on your method.

您收到错误的原因'T' is not convertible to 'T'是您实际上是在您的方法中定义了一个与原始 T 完全无关的T。如果您想在您的方法中使用 T,您可以这样做而无需在您的方法中指定它。

The reason that you get the second error 'AnyObject' is not convertible to 'T'is that all possible values for T are not all classes. For an instance to be converted to AnyObject, it must be a class (it cannot be a struct, enum, etc.).

出现第二个错误的原因'AnyObject' is not convertible to 'T'是 T 的所有可能值都不是所有类。对于要转换为 AnyObject 的实例,它必须是一个类(不能是结构体、枚举等)。

Your best bet is to make it a function that accepts the array as an argument:

最好的办法是使它成为一个接受数组作为参数的函数:

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) {
}

Or instead of modifying the original array, you can make your method more thread safe and reusable by returning a copy:

或者,您可以通过返回一个副本来使您的方法更加线程安全和可重用,而不是修改原始数组:

func arrayRemovingObject<T : Equatable>(object: T, fromArray array: [T]) -> [T] {
}

As an alternative that I don't recommend, you can have your method fail silently if the type stored in the array cannot be converted to the the methods template (that is equatable). (For clarity, I am using U instead of T for the method's template):

作为我不推荐的替代方法,如果存储在数组中的类型无法转换为方法模板(即 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]

EditTo overcome the silent failure you can return the success as a bool:

编辑要克服无声失败,您可以将成功返回为布尔值:

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

回答by János

briefly and concisely:

简明扼要地:

func removeObject<T : Equatable>(object: T, inout fromArray array: [T]) 
{
    var index = find(array, object)
    array.removeAtIndex(index!)
}

回答by December

After reading all the above, to my mind the best answer is:

看完以上所有内容后,我认为最好的答案是:

func arrayRemovingObject<U: Equatable>(object: U, # fromArray:[U]) -> [U] {
  return fromArray.filter { return 
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = arrayRemovingObject("Cat", fromArray:myArray )
!= object } }

Sample:

样本:

extension Array where Element: Equatable {  
  func arrayRemovingObject(object: Element) -> [Element] {  
    return filter { 
var myArray = ["Dog", "Cat", "Ant", "Fish", "Cat"]
myArray = myArray.arrayRemovingObject("Cat" )
!= object } } }

Swift 2 (xcode 7b4) array extension:

Swift 2 (xcode 7b4) 数组扩展:

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
    }
}

Sample:

样本:

// 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"]

Swift 3.1 update

斯威夫特 3.1 更新

Came back to this now that Swift 3.1 is out. Below is an extension which provides exhaustive, fast, mutating and creating variants.

现在 Swift 3.1 已经出来了。下面是一个提供详尽、快速、变异和创建变体的扩展。

extension Array where Element: Equatable {
    mutating func remove(object: Element) {
        if let index = indexOf({ 
extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = indexOf({ 
extension Array where Element: AnyObject {
    mutating func remove(object: Element) {
        if let index = index(where: { 
extension _ArrayType where Generator.Element : Equatable{
    mutating func removeObject(object : Self.Generator.Element) {
        while let index = self.indexOf(object){
            self.removeAtIndex(index)
        }
    }
}
=== object }) { remove(at: index) } } }
=== object }) { removeAtIndex(index) } } }
== object }) { removeAtIndex(index) } } }

Samples:

样品:

import Foundation
extension Array {
    mutating func removeObject<T where T : Equatable>(obj: T) {
        self = self.filter({
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: { 
//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
}
== 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]
as? T != obj}) } }

回答by Sri Krishna Paritala

With protocol extensions you can do this,

使用协议扩展,您可以做到这一点,

var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { 
let date1 = NSDate()
let date2 = NSDate()
var array = [date1, date2]
array.removeFirst(NSDate()) { 
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
          }
       }
   }   
}
=== } //won't do anything array.removeFirst(date1) { ##代码## === } //array now contains only 'date2'
== } //Banana is now removed

Same functionality for classes,

类的相同功能,

Swift 2

斯威夫特 2

##代码##

Swift 3

斯威夫特 3

##代码##

But if a class implements Equatable it becomes ambiguous and the compiler gives an throws an error.

但是如果一个类实现了 Equatable 它就会变得不明确并且编译器会抛出一个错误。

回答by ogantopkaya

With using protocol extensions in swift 2.0

在 swift 2.0 中使用协议扩展

##代码##

回答by valvoline

what about to use filtering? the following works quite well even with [AnyObject].

使用过滤怎么样?即使使用 [AnyObject],以下内容也能很好地工作。

##代码##

回答by Roi Zakai

No need to extend:

无需扩展:

##代码##

回答by borchero

There is another possibility of removing an item from an array without having possible unsafe usage, as the generic type of the object to remove cannot be the same as the type of the array. Using optionals is also not the perfect way to go as they are very slow. You could therefore use a closure like it is already used when sorting an array for example.

还有另一种可能性,可以在不存在不安全使用的情况下从数组中删除项目,因为要删除的对象的泛型类型不能与数组的类型相同。使用 optionals 也不是完美的方式,因为它们非常慢。因此,您可以使用闭包,就像在对数组进行排序时已经使用的那样。

##代码##

When you extend the Arrayclass with this function you can remove elements by doing the following:

当您Array使用此函数扩展类时,您可以通过执行以下操作来删除元素:

##代码##

However you could even remove an element only if it has the same memory address (only for classes conforming to AnyObjectprotocol, of course):

但是,您甚至可以仅删除具有相同内存地址的元素(AnyObject当然,仅适用于符合协议的类):

##代码##

The good thing is, that you can specify the parameter to compare. For example when you have an array of arrays, you can specify the equality closure as { $0.count == $1.count }and the first array having the same size as the one to remove is removed from the array.

好消息是,您可以指定要比较的参数。例如,当您有一个数组数组时,您可以指定等式闭包为,{ $0.count == $1.count }并且从数组中删除与要删除的数组具有相同大小的第一个数组。

You could even shorten the function call by having the function as mutating func removeFirst(equality: (Element) -> Bool) -> Bool, then replace the if-evaluation with equality(item)and call the function by array.removeFirst({ $0 == "Banana" })for example.

您甚至可以通过将函数设为 来缩短函数调用mutating func removeFirst(equality: (Element) -> Bool) -> Bool,然后将 if-evaluation 替换为equality(item)并通过array.removeFirst({ $0 == "Banana" })例如调用函数。

回答by juanjo

Using indexOfinstead of a foror enumerate:

使用indexOf代替 aforenumerate

##代码##