Menghapus objek dari array di Swift 3

93

Dalam aplikasi saya, saya menambahkan satu objek dalam array ketika memilih sel dan membatalkan pilihan dan menghapus objek saat memilih ulang sel. Saya menggunakan kode itu tetapi memberi saya kesalahan.

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

Ini memberi saya 2 kesalahan seperti itu:

C-style for statement has been removed in Swift 3
Value of type '[Any]' has no member 'removeObject'
Kamlesh Shingarakhiya
sumber
Anda dapat menggunakan Set<Contact>daripada Array. Dapatkah Anda memberikan lebih banyak informasi tentang objek kontak Anda? Jika Anda membuatnya sendiri, Anda akan membutuhkannya untuk menyesuaikan Hashabledan Equatableuntuk meletakkannya dalam satu set
Paulw11

Jawaban:

167

Persamaan Swift dengan NSMutableArray's removeObjectadalah:

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

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

jika objeknya unik . Tidak perlu sama sekali untuk mentransmisikan NSArraydan menggunakanindexOfObject:

API index(of:juga berfungsi tetapi hal ini menyebabkan transmisi implisit yang tidak perlu dilakukan NSArray.

Jika ada beberapa kejadian penggunaan objek yang sama filter. Namun dalam kasus seperti larik sumber data di mana indeks dikaitkan dengan objek tertentu firstIndex(oflebih disukai karena lebih cepat daripada filter.

Memperbarui:

Di Swift 4.2+ Anda dapat menghapus satu atau beberapa kejadian betadengan removeAll(where:):

array.removeAll{$0 == "beta"}
vadian
sumber
34
Ini adalah jawaban terbaik, tetapi sangat bodoh untuk tidak menghapusnya (object: "beta").
zeeple
5
Menurut saya .index(of: hanya tersedia jika koleksi berisi Equatablejenis.
Adam Waite
@AdamWaite Ya, tetapi ini juga berlaku untuk jenis Foundation.
vadian
Ini tidak benar, bagaimana jika Anda memiliki lebih dari satu "beta"? Ini hanya berfungsi jika array tidak berisi lebih dari satu kejadian. Jawaban yang benar adalah menggunakan filter atau menjalankan jawaban ini sebentar lagi,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla
@juancazalla Anda benar, tetapi dalam kasus jika array dapat berisi lebih dari satu kejadian, gunakan filtersolusi. Tetapi jika objeknya unik, gunakan selalu index(ofkarena performanya jauh lebih baik daripadafilter
vadian
72
var a = ["one", "two", "three", "four", "five"]

// Remove/filter item with value 'three'
a = a.filter { $0 != "three" }
nyxee
sumber
7
Itu adalah solusi Swift yang tepat, yang memanfaatkan barang sintaksis yang ditawarkan oleh bahasa tersebut.
Michael
1
Bagaimana jika barang adalah benda?
TomSawyer
@TomSawyer untuk menyaring objek, gunakan $ 0! ==
Mike Taverne
25

Untuk Swift 3, Anda dapat menggunakan index (di mana :) dan menyertakan closure yang melakukan perbandingan objek dalam array ($ 0) dengan apa pun yang Anda cari.

var array = ["alpha", "beta", "gamma"]
if let index = array.index(where: {$0 == "beta"}) {
  array.remove(at: index)
}
Mark Semsel
sumber
apakah ini akan berfungsi jika saya ingin menghapus beberapa objek? suka (di mana: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed
16

Solusi bagus dan berguna lainnya adalah dengan membuat ekstensi semacam ini:

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
    }

}

Dengan cara ini, jika Anda memiliki array Anda dengan objek kustom:

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) 
Luca Davanzo
sumber
1
Ini hanya berfungsi jika array tidak berisi lebih dari satu kejadian. Jawaban yang benar adalah menggunakan filter atau menjalankan jawaban ini sebentar. Sebagai pengguna ekstensi ini, saya mengharapkannya untuk menghapus semua kejadian dan tidak hanya satu
juancazalla
Itu bagus, tetapi seharusnya remove(element: Element)karena dalam Array Anda juga dapat menyimpan tipe seperti Int, Double - mereka bukan objek.
Radek Wilczak
8

Di Swift 5 , Gunakan ini Extension:

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

contoh:

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

Di Swift 3 , Gunakan ini Extension:

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

contoh:

var array = ["alpha", "beta", "gamma"]
array.remove(element: "beta")
Mohsenasm
sumber
6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) adalah untuk loop dalam gaya C dan telah dihapus

  2. Ubah kode Anda menjadi sesuatu seperti ini untuk menghapus semua objek serupa jika telah berulang:

    let indexes = arrContacts.enumerated().filter { $0.element == contacts[indexPath.row] }.map{ $0.offset }
    for index in indexes.reversed() {
       arrContacts.remove(at: index)
    }
    
Tj3n
sumber
enumerated -> filter -> map and remove (at) adalah solusi cerdas. Rekomendasikan yang ini
Ryan X
4

Cepat 4

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

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

Solusi satu baris yang benar dan berfungsi untuk menghapus objek unik (bernama "objectToRemove") dari array objek ini (bernama "array") di Swift 3 adalah:

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

Coba ini di Swift 3

array.remove(at: Index)

Dari pada

array.removeAtIndex(index)

Memperbarui

"Declaration is only valid at file scope".

Pastikan objek dalam ruang lingkup. Anda dapat memberikan ruang lingkup "internal", yang default.

index(of:<Object>) untuk bekerja, kelas harus sesuai Equatable

Dili
sumber
1

Di Swift 3 dan 4

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

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

Dari Swift 4.2 Anda dapat menggunakan pendekatan yang lebih canggih (lebih cepat dan hemat memori)

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

dari pada

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

Baca lebih lanjut di sini

yoAlex5
sumber
1

Ekstensi untuk array untuk melakukannya dengan mudah dan memungkinkan perangkaian untuk Swift 4.2 dan yang lebih baru:

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
    }
}
Renetik
sumber
Label argumen '(di mana :)' tidak cocok dengan kelebihan beban yang tersedia
jeet.chanchawat
1
@ jeet.chanchawat yah mungkin versi swiftnya berbeda ... Oh pertanyaan ini untuk 3? Yah saya pikir saya punya 4.2 pada saat menulis tetapi tidak ingat sekarang, akan memeriksanya nanti, itu pasti berhasil untuk saya
Renetik
0

Ini adalah jawaban resmi untuk mencari indeks objek tertentu, maka Anda dapat dengan mudah menghapus objek apa pun menggunakan indeks itu:

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"]

Ini tautannya: https://developer.apple.com/documentation/swift/array/2994720-firstindex

Mahesh Cheliya
sumber
0

Ini yang saya gunakan (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)

Hasil:

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

Penting: Larik tempat Anda menghapus item harus berisi elemen yang dapat disamakan (seperti objek, string, angka, dll.)

Kerajaan Andrew
sumber