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
Как правильно это сделать?
T where
из своего объявления метода. Так что простоfunc removeObject<T: Equatable>
. Этот вопрос связан: stackoverflow.com/questions/24091046/...Ответы:
Начиная с 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]
Обновление для 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) } } }
источник
remove(object: Element)
в, чтобы соответствовать рекомендациям по дизайну Swift API и избежать многословия. Я отправил правку, отражающую это.Вы не можете написать метод для универсального типа, который является более строгим для шаблона.
ПРИМЕЧАНИЕ. Начиная с Swift 2.0, теперь вы можете писать методы, которые более ограничивают шаблон. Если вы обновили свой код до версии 2.0, см. Другие ответы ниже, чтобы узнать о новых вариантах реализации этого с помощью расширений.
Причина, по которой вы получаете ошибку,
'T' is not convertible to 'T'
заключается в том, что вы фактически определяете новый T в своем методе, который вообще не связан с исходным 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]
Изменить Чтобы преодолеть тихую неудачу, вы можете вернуть успех как 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
источник
find
метод?Equatable
протокол. UIView делает это, да, он будет работать с UIViewsenumerate(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) } } }
Та же функциональность для классов,
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, он становится неоднозначным, и компилятор выдает ошибку.
источник
Binary operator '===' cannot be applied to two elements of type '_' and 'Element'
С использованием расширений протокола в 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}) } }
источник
Существует еще одна возможность удаления элемента из массива без возможного небезопасного использования, поскольку общий тип удаляемого объекта не может совпадать с типом массива. Использование дополнительных опций также не лучший способ, поскольку они очень медленные. Поэтому вы можете использовать закрытие, как, например, оно уже используется при сортировке массива.
//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-оценка на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
источник
В конце концов я получил следующий код.
extension Array where Element: Equatable { mutating func remove<Element: Equatable>(item: Element) -> Array { self = self.filter { $0 as? Element != item } return self } }
источник
Мне удалось удалить
[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 } } }
источник
Мне удалось заставить его работать с:
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!) } } }
источник
if(index)
недействительно