값으로 객체를 제거하는 배열 확장
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를 사용하려면 메소드에 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을 구현하면 모호 해지고 컴파일러에서 오류가 발생합니다.
With using protocol extensions in 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)
}
}
}
what about to use filtering? the following works quite well even with [AnyObject].
import Foundation
extension Array {
mutating func removeObject<T where T : Equatable>(obj: T) {
self = self.filter({$0 as? T != obj})
}
}
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.
//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
}
When you extend the Array
class with this function you can remove elements by doing the following:
var array = ["Apple", "Banana", "Strawberry"]
array.removeFirst("Banana") { $0 == $1 } //Banana is now removed
However you could even remove an element only if it has the same memory address (only for classes conforming to AnyObject
protocol, of course):
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'
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.
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.
Using indexOf
instead of a for
or 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
}
}
}
}
Maybe I didn't understand the question.
Why wouldn't this work?
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
I finally ended up with following code.
extension Array where Element: Equatable {
mutating func remove<Element: Equatable>(item: Element) -> Array {
self = self.filter { $0 as? Element != item }
return self
}
}
I managed to remove a [String:AnyObject]
from an array [[String:AnyObject]]
by implementing a count outside of a for loop to represent the index since .find
and .filter
are not compatible with [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
}
Implementation in 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
}
}
}
I was able to get it working with:
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!)
}
}
}
참고URL : https://stackoverflow.com/questions/24938948/array-extension-to-remove-object-by-value
'Programing' 카테고리의 다른 글
jQuery에서 요소의 n 번째 수준 부모를 얻으려면 어떻게해야합니까? (0) | 2020.06.20 |
---|---|
리눅스에서 bash로 어제 날짜 가져 오기, DST 안전 (0) | 2020.06.20 |
Java의 각 루프마다 역순으로 할 수 있습니까? (0) | 2020.06.20 |
최대 높이를 설정 해제하는 방법? (0) | 2020.06.19 |
파이썬의 유휴 창을 지우는 방법은 무엇입니까? (0) | 2020.06.19 |