Usuwanie obiektu z tablicy w Swift 3


93

W mojej aplikacji dodałem jeden obiekt w tablicy po zaznaczeniu komórki i odznaczeniu i usunięciu obiektu po ponownym wybraniu komórki. Użyłem tego kodu, ale daj mi błąd.

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

Daje mi 2 takie błędy:

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

Możesz użyć Set<Contact>raczej niż Array. Czy możesz podać więcej informacji na temat przedmiotu kontaktu? Jeśli zrobiłeś to sam, będziesz potrzebować go, aby dostosować się Hashablei Equatableumieścić go w zestawie
Paulw11

Odpowiedzi:


166

Swift odpowiednikiem NSMutableArray's removeObjectto:

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

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

jeśli obiekty są unikalne . W ogóle nie ma potrzeby rzucania NSArrayi używaniaindexOfObject:

Interfejs API index(of:również działa, ale powoduje to niepotrzebne niejawne rzutowanie mostu do NSArray.

Jeśli istnieje wiele wystąpień tego samego obiektu, użyj filter. Jednak w przypadkach, takich jak tablice źródeł danych, w których indeks jest powiązany z określonym obiektem, firstIndex(ofjest preferowany, ponieważ jest szybszy niż filter.

Aktualizacja:

W Swift 4.2+ możesz usunąć jedno lub wiele wystąpień za betapomocą removeAll(where:):

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

34
To najlepsza odpowiedź, ale głupotą jest nie mieć usunięcia (obiekt: „beta”).
zeeple

5
Myślę, że .index(of: jest dostępny tylko wtedy, gdy kolekcja zawiera Equatabletypy.
Adam Waite

@AdamWaite Tak, ale dotyczy to również typów Fundacji.
vadian

To nie jest w porządku, a co jeśli masz więcej niż jedną wersję „beta”? Działa to tylko wtedy, gdy tablica nie zawiera więcej niż jednego wystąpienia. Prawidłowa odpowiedź to użycie filtra lub uruchomienie tej odpowiedzi za chwilę,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazalla Masz rację, ale w przypadku, gdy tablica może zawierać więcej niż jedno wystąpienie, użyj filterrozwiązania. Ale jeśli przedmioty są wyjątkowe, zawsze używaj ich, index(ofponieważ są znacznie bardziej wydajne niżfilter
vadian

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

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

7
To jest poprawne rozwiązanie Swift, które korzysta z dobrodziejstw składni oferowanych przez język.
Michael,

1
A jeśli przedmiot jest przedmiotem?
TomSawyer

@TomSawyer, aby odfiltrować obiekt, użyj $ 0! ==
Mike Taverne

25

W przypadku Swift 3 możesz użyć indeksu (gdzie :) i dołączyć zamknięcie, które porównuje obiekt w tablicy ($ 0) z tym, czego szukasz.

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

czy to zadziała, jeśli chcę usunąć wiele obiektów? jak (gdzie: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed

16

Kolejnym fajnym i przydatnym rozwiązaniem jest stworzenie takiego rozszerzenia:

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
    }

}

W ten sposób, jeśli masz tablicę z niestandardowymi obiektami:

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
Działa to tylko wtedy, gdy tablica nie zawiera więcej niż jednego wystąpienia. Prawidłowa odpowiedź to użycie filtra lub uruchomienie tej odpowiedzi za jakiś czas. Jako użytkownik tego rozszerzenia oczekuję, że usunie wszystkie wystąpienia, a nie tylko jedno
juancazalla

To fajne, ale powinno być, remove(element: Element)ponieważ w Array możesz przechowywać również typy takie jak Int, Double - nie są to obiekty.
Radek Wilczak

8

W Swift 5 użyj tego Extension:

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

przykład:

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

W Swift 3 użyj tego Extension:

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

przykład:

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

6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) jest dla pętli w stylu C i został usunięty

  2. Zmień kod na coś takiego, aby usunąć wszystkie podobne obiekty, jeśli zostały zapętlone:

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

enumerated -> filter -> map and remove (at) to inteligentne rozwiązanie. Polecam ten
Ryan X

4

Szybki 4

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

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

3

Prawidłowe i działające jednowierszowe rozwiązanie do usuwania unikalnego obiektu (o nazwie „objectToRemove”) z tablicy tych obiektów (o nazwie „tablica”) w języku Swift 3 to:

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

1

Spróbuj tego w Swift 3

array.remove(at: Index)

Zamiast

array.removeAtIndex(index)

Aktualizacja

"Declaration is only valid at file scope".

Upewnij się, że obiekt jest w zasięgu. Możesz określić zakres jako „wewnętrzny”, co jest wartością domyślną.

index(of:<Object>) do pracy, klasa powinna się dostosować Equatable


1

W Swift 3 i 4

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

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

Od wersji Swift 4.2 możesz zastosować bardziej zaawansowane podejście (szybsze i wydajniejsze pod względem pamięci)

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

zamiast

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

Przeczytaj więcej tutaj


1

Rozszerzenie dla array, aby zrobić to łatwo i umożliwić łączenie w łańcuch dla Swift 4.2 i nowszych:

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

Etykiety argumentów „(gdzie :)” nie pasują do żadnych dostępnych przeciążeń
jeet.chanchawat

1
@ jeet.chanchawat no chyba w innej wersji swift ... Och to pytanie dotyczyło 3? Cóż, myślę, że miałem 4.2 w momencie pisania, ale nie pamiętam teraz, sprawdzę później, na pewno zadziałało mi
Renetik


0

To jest to, czego użyłem (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)

Wyniki:

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

Ważne: tablica, z której usuwasz elementy, musi zawierać elementy Equatable (takie jak obiekty, ciągi znaków, liczba itp.)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.