Chcę wyliczyć tablicę w Swift i usunąć niektóre elementy. Zastanawiam się, czy jest to bezpieczne, a jeśli nie, to jak mam to osiągnąć.
Obecnie robiłbym to:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
ios
arrays
swift
enumeration
Andrzej
źródło
źródło
filter
zwraca nową tablicę. Nie usuwasz niczego z tablicy. Nie nazwałbym nawetfilter
wyliczenia. Zawsze jest więcej niż jeden sposób na oskórowanie kota.Możesz rozważyć
filter
sposób:var theStrings = ["foo", "bar", "zxy"] // Filter only strings that begins with "b" theStrings = theStrings.filter { $0.hasPrefix("b") }
Parametr of
filter
to po prostu zamknięcie, które przyjmuje instancję typu tablicowego (w tym przypadkuString
) i zwraca wartośćBool
. Kiedy wynik jesttrue
, zachowuje element, w przeciwnym razie element jest odfiltrowywany.źródło
filter
nie aktualizuje tablicy, po prostu zwraca nowąfilter
metodę wmutating
jedną (ponieważ przeczytałem, żemutating
słowo kluczowe umożliwiaself
zamiast tego zmianę funkcji takich jak ta )?Array
oznaczania go jakomutating
i podobnego do kodu pytania. W każdym razie weź pod uwagę, że nie zawsze może to być zaletą. W każdym razie za każdym razem, gdy usuwasz obiekt, twoja tablica może zostać zreorganizowana w pamięci. W ten sposób może być bardziej wydajne przydzielenie nowej tablicy, a następnie wykonanie atomowego podstawienia wynikiem funkcji filtrującej. Kompilator może wykonać jeszcze więcej optymalizacji, w zależności od kodu.W Swift 3 i 4 wyglądałoby to tak:
Z liczbami, zgodnie z odpowiedzią Johnstona:
var a = [1,2,3,4,5,6] for (i,num) in a.enumerated().reversed() { a.remove(at: i) } print(a)
Ze stringami jako pytaniem OP:
var b = ["a", "b", "c", "d", "e", "f"] for (i,str) in b.enumerated().reversed() { if str == "c" { b.remove(at: i) } } print(b)
Jednak teraz w wersji Swift 4.2 lub nowszej istnieje jeszcze lepszy, szybszy sposób, który został zalecony przez Apple w WWDC2018:
var c = ["a", "b", "c", "d", "e", "f"] c.removeAll(where: {$0 == "c"}) print(c)
Ten nowy sposób ma kilka zalet:
filter
.źródło
{$0 === Class.self}
nie działaGdy element o określonym indeksie zostanie usunięty z tablicy, pozycja (i indeks) wszystkich kolejnych elementów zostanie zmieniona, ponieważ cofną się o jedną pozycję.
Najlepszym sposobem jest więc nawigowanie po tablicy w odwrotnej kolejności - w tym przypadku sugeruję użycie tradycyjnej pętli for:
for var index = array.count - 1; index >= 0; --index { if condition { array.removeAtIndex(index) } }
Jednak moim zdaniem najlepszym podejściem jest zastosowanie
filter
metody opisanej przez @perlfly w swojej odpowiedzi.źródło
Nie, mutowanie tablic podczas wyliczania nie jest bezpieczne, twój kod ulegnie awarii.
Jeśli chcesz usunąć tylko kilka obiektów, możesz skorzystać z
filter
funkcji.źródło
filter
jest bezpieczniejsze . Oto mój głupi przykład:var y = [1, 2, 3, 4, 5]; print(y); for (index, value) in y.enumerated() { y.remove(at: index) } print(y)
Utwórz zmienną tablicę do przechowywania elementów do usunięcia, a następnie po wyliczeniu usuń te elementy z oryginału. Lub utwórz kopię tablicy (niezmienną), wylicz ją i usuń obiekty (nie według indeksu) z oryginału podczas wyliczania.
źródło
Tradycyjną pętlę for można zastąpić prostą pętlą while, przydatną, jeśli przed usunięciem trzeba wykonać również inne operacje na każdym elemencie.
var index = array.count-1 while index >= 0 { let element = array[index] //any operations on element array.remove(at: index) index -= 1 }
źródło
Polecam ustawić elementy na nil podczas wyliczania, a po zakończeniu usunąć wszystkie puste elementy za pomocą metody Arrays filter ().
źródło
filter
metoda nie usuwa, generuje nową tablicę.Wystarczy dodać, że jeśli masz wiele tablic i każdy element w indeksie N tablicy A jest powiązany z indeksem N tablicy B, to nadal możesz użyć metody odwracającej wyliczoną tablicę (jak poprzednie odpowiedzi). Pamiętaj jednak, że podczas uzyskiwania dostępu i usuwania elementów innych tablic nie ma potrzeby ich odwracania.
Like so, (one can copy and paste this on Playground) var a = ["a", "b", "c", "d"] var b = [1, 2, 3, 4] var c = ["!", "@", "#", "$"] // remove c, 3, # for (index, ch) in a.enumerated().reversed() { print("CH: \(ch). INDEX: \(index) | b: \(b[index]) | c: \(c[index])") if ch == "c" { a.remove(at: index) b.remove(at: index) c.remove(at: index) } } print("-----") print(a) // ["a", "b", "d"] print(b) // [1, 2, 4] print(c) // ["!", "@", "$"]
źródło