[ios] 값으로 객체를 제거하는 배열 확장

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’로 변환 할 수 없습니다

이를 수행하는 올바른 방법은 무엇입니까?



답변

현재 스위프트 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]

Swift 2 / Xcode 7 베타 2 업데이트 : Airspeed Velocity가 주석에서 알 수 있듯이 템플릿에서 더 제한적인 제네릭 형식에 대한 메서드를 실제로 작성할 수 있으므로 이제 메서드를 실제로 확장으로 정의 할 수 있습니다. 중 Array:

extension Array where Element : Equatable {

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

프로토콜 확장은 더 큰 유형의 세트에 적용 할 수 있다는 장점이 있습니다.

스위프트 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)
        }
    }
}


답변

템플릿에서 더 제한적인 제네릭 형식에는 메서드를 작성할 수 없습니다.

참고 : 스위프트 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] {
}

권장하지 않는 대안으로 배열에 저장된 유형을 메소드 템플리트로 변환 할 수없는 경우 메소드가 자동으로 실패하도록 할 수 있습니다 (즉, 동일). (명확하게하기 위해 메서드 템플릿에 T 대신 U를 사용하고 있습니다)

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 )

스위프트 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" )

스위프트 3.1 업데이트

이제 스위프트 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"]


답변

프로토콜 확장으로이 작업을 수행 할 수 있습니다.

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을 구현하면 모호 해지고 컴파일러에서 오류가 발생합니다.


답변

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

}