Видалення об’єкта з масиву в Swift 3


92

У моїй програмі я додав один об'єкт у масив при виділенні комірки та скасував вибір та видалення об'єкта при повторному виділенні комірки. Я використав цей код, але дав мені помилку.

extension Array {
    func indexOfObject(object : AnyObject) -> NSInteger {
        return (self as NSArray).indexOfObject(object)
    }

    mutating func removeObject(object : AnyObject) {
        for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) {
            self.removeAtIndex(index)
        }
    }
}

class MyViewController: UITableViewController {
    var arrContacts: [Any] = []
    var contacts: [Any] = []

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        arrContacts.removeObject(contacts[indexPath.row])
    }
}

Це дає мені 2 такі помилки:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'

Ви можете використовувати Set<Contact>не масив, а масив. Чи можете ви надати більше інформації про свій контактний об'єкт? Якщо ви зробили це самостійно, вам потрібно буде відповідати Hashableі Equatableдля того, щоб скласти його в наборі
Paulw11,

Відповіді:


164

Свіфт, еквівалентний NSMutableArray's removeObject:

var array = ["alpha", "beta", "gamma"]

if let index = array.firstIndex(of: "beta") {
    array.remove(at: index)
}

якщо об’єкти унікальні . Взагалі немає необхідності кидати NSArrayі використовуватиindexOfObject:

API index(of:також працює, але це призводить до непотрібного неявного мосту до NSArray.

Якщо є кілька випадків використання одного і того ж об'єкта filter. Однак у таких випадках, як масиви джерел даних, де індекс пов'язаний з певним об'єктом firstIndex(of, переважно, оскільки це швидше, ніж filter.

Оновлення:

У Swift 4.2+ ви можете видалити одне або кілька випадків з betaдопомогою removeAll(where:):

array.removeAll{$0 == "beta"}

33
Це найкраща відповідь, але дурним є відсутність видалення (об'єкт: "бета").
zeeple

5
Я думаю, що .index(of: це доступно, лише якщо колекція містить Equatableтипи.
Адам Уейт

@AdamWaite Так, але це стосується і типів Фонду.
vadian

Це неправильно, а що, якщо у вас є кілька "бета"? Це працює, лише якщо масив не містить більше одного входження. Правильною відповіддю є використання фільтра або запуск цієї відповіді через деякий час,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazalla Ви маєте рацію, але у випадку, якщо масив може містити більше одного входження, використовуйте filterрішення. Але якщо об’єкти унікальні, використовуйте завжди, index(ofтому що вони набагато ефективніші, ніжfilter
vadian

71
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }

7
Це правильне рішення Swift, яке використовує синтаксичні ласощі, пропоновані мовою.
Майкл

1
Що робити, якщо предмет є об’єктом?
TomSawyer

@TomSawyer, щоб відфільтрувати об’єкт, використовуй $ 0! ==
Mike Taverne

25

Для Swift 3 ви можете використовувати index (where :) і включити закриття, яке робить порівняння об’єкта в масиві ($ 0) з тим, що ви шукаєте.

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}

це спрацює, якщо я хочу видалити кілька об’єктів? як (де: {$ 0 == "beta" || $ 0 == "gamma"})
Іршад Мохамед

16

Ще одним приємним та корисним рішенням є створення такого типу розширення:

extension Array where Element: Equatable {

    @discardableResult mutating func remove(object: Element) -> Bool {
        if let index = index(of: object) {
            self.remove(at: index)
            return true
        }
        return false
    }

    @discardableResult mutating func remove(where predicate: (Array.Iterator.Element) -> Bool) -> Bool {
        if let index = self.index(where: { (element) -> Bool in
            return predicate(element)
        }) {
            self.remove(at: index)
            return true
        }
        return false
    }

}

Таким чином, якщо у вас є масив із користувацькими об’єктами:

let obj1 = MyObject(id: 1)
let obj2 = MyObject(id: 2)
var array: [MyObject] = [obj1, obj2]

array.remove(where: { (obj) -> Bool in
    return obj.id == 1
})
// OR
array.remove(object: obj2) 

1
Це працює, лише якщо масив не містить більше одного входження. Правильною відповіддю є використання фільтра або запуск цієї відповіді через деякий час. Як користувач цього розширення, я сподіваюся, що воно видалить усі випадки, і не тільки одне
juancazalla

Це приємно, але це повинно бути, remove(element: Element)тому що в Array ви можете зберігати також такі типи, як Int, Double - вони не є об’єктами.
Радек Вільчак

8

У Swift 5 використовуйте це Extension:

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.firstIndex(of: element) {
            self.remove(at: i)
        }
    }
}

приклад:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")

У Swift 3 використовуйте це Extension:

extension Array where Element: Equatable{
    mutating func remove (element: Element) {
        if let i = self.index(of: element) {
            self.remove(at: i)
        }
    }
}

приклад:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")

6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) є для циклу в стилі C і був видалений

  2. Змініть свій код на щось подібне, щоб видалити всі подібні об’єкти, якщо вони циклічні:

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    

перераховане -> фільтр -> зіставити та видалити (at) є розумним рішенням. Рекомендуйте цей
Райан Х,

4

Стрімкий 4

var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]

if let index = students.firstIndex(where: { $0.hasPrefix("A") }) {
   students.remove(at: index)
}

3

Правильним та діючим однорядковим рішенням для видалення унікального об'єкта (з назвою "objectToRemove") з масиву цих об'єктів (з назвою "масив") у Swift 3 є:

if let index = array.enumerated().filter( { $0.element === objectToRemove }).map({ $0.offset }).first {
   array.remove(at: index)
}

1

Спробуйте це в Swift 3

array.remove(at: Index)

Замість

array.removeAtIndex(index)

Оновлення

"Declaration is only valid at file scope".

Переконайтесь, що об’єкт знаходиться в зоні дії. Ви можете вказати область "внутрішня", яка є типовою.

index(of:<Object>) щоб працювати, клас повинен відповідати Equatable


1

У Swift 3 і 4

var array = ["a", "b", "c", "d", "e", "f"]

for (index, element) in array.enumerated().reversed() {
    array.remove(at: index)
}

У Swift 4.2 ви можете використовувати більш просунутий підхід (швидший та ефективніший з пам'яттю)

array.removeAll(where: { $0 == "c" })

замість

array = array.filter { !$0.hasPrefix("c") }

Детальніше читайте тут


1

Розширення для масиву, щоб зробити це легко і дозволити ланцюжок для Swift 4.2 і вище:

public extension Array where Element: Equatable {
    @discardableResult
    public mutating func remove(_ item: Element) -> Array {
        if let index = firstIndex(where: { item == $0 }) {
            remove(at: index)
        }
        return self
    }

    @discardableResult
    public mutating func removeAll(_ item: Element) -> Array {
        removeAll(where: { item == $0 })
        return self
    }
}

Мітки аргументів '(де :)' не відповідають жодним доступним перевантаженням
jeet.chanchawat

1
@ jeet.chanchawat ну, мабуть, інша швидка версія тоді ... О це питання було для 3? Ну, думаю, у мене було 4,2 на момент написання статті, але не пам’ятаю зараз, перевірю це пізніше, це точно спрацювало для мене
Ренетік

0

Це офіційна відповідь на пошук індексу конкретного об'єкта, тоді ви можете легко видалити будь-який об'єкт, використовуючи цей індекс:

var students = ["Ben", "Ivy", "Jordell", "Maxime"]
if let i = students.firstIndex(of: "Maxime") {
     // students[i] = "Max"
     students.remove(at: i)
}
print(students)
// Prints ["Ben", "Ivy", "Jordell"]

Ось посилання: https://developer.apple.com/documentation/swift/array/2994720-firstindex


0

Це те, що я використовував (Swift 5) ...

    extension Array where Element:Equatable
    {
        @discardableResult
        mutating func removeFirst(_ item:Any ) -> Any? {
            for index in 0..<self.count {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
            }
            return nil
        }
        @discardableResult
        mutating func removeLast(_ item:Any ) -> Any? {
            var index = self.count-1
            while index >= 0 {
                if(item as? Element == self[index]) {
                    return self.remove(at: index)
                }
                index -= 1
            }
            return nil
        }
    }

    var arrContacts:[String] = ["A","B","D","C","B","D"]
    var contacts: [Any] = ["B","D"]
    print(arrContacts)
    var index = 1
    arrContacts.removeFirst(contacts[index])
    print(arrContacts)
    index = 0
    arrContacts.removeLast(contacts[index])
    print(arrContacts)

Результати:

   ["A", "B", "D", "C", "B", "D"]
   ["A", "B", "C", "B", "D"]
   ["A", "B", "C", "D"]

Важливо: Масив, з якого ви вилучаєте елементи, повинен містити елементи, що вирівнюються (наприклад, об’єкти, рядки, число тощо).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.