การลบวัตถุออกจากอาร์เรย์ใน Swift 3


93

ในแอปพลิเคชันของฉันฉันเพิ่มวัตถุหนึ่งชิ้นในอาร์เรย์เมื่อเลือกเซลล์และยกเลิกการเลือกและลบวัตถุเมื่อเลือกเซลล์ใหม่ ฉันใช้รหัสนั้น แต่ให้ข้อผิดพลาด

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>แทน Array ได้ คุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับวัตถุติดต่อของคุณได้หรือไม่? หากคุณสร้างมันขึ้นมาเองคุณจะต้องใช้มันเพื่อให้สอดคล้องHashableและEquatableเพื่อที่จะใส่ไว้ในชุด
Paulw11

คำตอบ:


167

เทียบเท่าสวิฟท์ที่จะ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(offilter

อัปเดต:

ใน Swift 4.2+ คุณสามารถลบเหตุการณ์หนึ่งหรือหลายเหตุการณ์ได้betaด้วยremoveAll(where:):

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

34
นี่เป็นคำตอบที่ดีที่สุด แต่มันก็เป็นเรื่องโง่มากที่จะไม่มีการลบ (object: "beta")
zeeple

5
ฉันคิดว่า.index(of: จะใช้ได้ก็ต่อเมื่อคอลเล็กชันมีEquatableประเภท
Adam Waite

@AdamWaite ใช่ แต่สิ่งนี้ใช้ได้กับประเภทของมูลนิธิด้วย
vadian

ไม่ถูกต้องจะเกิดอะไรขึ้นถ้าคุณมี "เบต้า" มากกว่าหนึ่ง สิ่งนี้ใช้ได้เฉพาะในกรณีที่อาร์เรย์ไม่มีเหตุการณ์มากกว่าหนึ่งครั้ง คำตอบที่ถูกต้องคือการใช้ตัวกรองหรือเรียกใช้คำตอบนี้ในอีกสักครู่while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazalla คุณพูดถูก แต่ในกรณีที่อาร์เรย์สามารถมีได้มากกว่าหนึ่งรายการให้ใช้filterวิธีแก้ปัญหา แต่ถ้าวัตถุที่มีการใช้งานที่ไม่ซ้ำกันเสมอindex(ofเพราะมันมากขึ้นกว่า performantfilter
Vadian

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

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

7
นั่นคือโซลูชัน Swift ที่ถูกต้องซึ่งใช้ประโยชน์จากไวยากรณ์ที่นำเสนอโดยภาษา
Michael

1
จะเกิดอะไรขึ้นถ้ารายการเป็นวัตถุ?
TomSawyer

@TomSawyer เพื่อกรองวัตถุใช้ $ 0! ==
Mike Taverne

25

สำหรับ Swift 3 คุณสามารถใช้ดัชนี (โดยที่ :) และรวมการปิดที่ทำการเปรียบเทียบวัตถุในอาร์เรย์ ($ 0) กับสิ่งที่คุณกำลังมองหา

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

จะใช้งานได้หรือไม่ถ้าฉันต้องการลบวัตถุหลายชิ้น เช่น (โดยที่: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed

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) เป็นโซลูชันที่ชาญฉลาด แนะนำอันนี้
Ryan X


3

โซลูชันบรรทัดเดียวที่ถูกต้องและใช้งานได้สำหรับการลบอ็อบเจ็กต์เฉพาะ (ชื่อ "objectToRemove") จากอาร์เรย์ของอ็อบเจ็กต์เหล่านี้ (ชื่อ "array") ใน 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 อาจจะเป็นเวอร์ชั่น swift ที่แตกต่างกันออกไป ... โอ้คำถามนี้สำหรับ 3 คน? ฉันคิดว่าฉันมี 4.2 ในขณะที่เขียน แต่จำไม่ได้ตอนนี้จะตรวจสอบในภายหลังมันใช้ได้กับฉันแน่นอน
Renetik

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

สำคัญ: อาร์เรย์ที่คุณนำไอเท็มออกต้องมีองค์ประกอบที่เท่ากันได้ (เช่นออบเจ็กต์สตริงตัวเลข ฯลฯ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.