Xóa đối tượng khỏi mảng trong Swift 3


93

Trong ứng dụng của tôi, tôi đã thêm một đối tượng trong mảng khi chọn ô và bỏ chọn và loại bỏ đối tượng khi chọn lại ô. Tôi đã sử dụng mã đó nhưng cho tôi lỗi.

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

Nó cho tôi 2 lỗi như vậy:

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

Bạn có thể sử dụng một Set<Contact>thay vì một Mảng. Bạn có thể cung cấp thêm thông tin về đối tượng liên hệ của mình không? Nếu bạn đã thực hiện điều đó cho mình, bạn sẽ cần nó để phù hợp với HashableEquatableđể đặt nó trong một tập
Paulw11

Câu trả lời:


167

Swift tương đương với NSMutableArray's removeObjectlà:

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

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

nếu các đối tượng là duy nhất . Không cần thiết phải truyền đến NSArrayvà sử dụngindexOfObject:

API index(of:cũng hoạt động nhưng điều này gây ra một cầu nối ngầm không cần thiết NSArray.

Nếu có nhiều lần xuất hiện cùng một đối tượng sử dụng filter. Tuy nhiên, trong các trường hợp như mảng nguồn dữ liệu trong đó chỉ mục được liên kết với một đối tượng cụ thể firstIndex(ofsẽ thích hợp hơn vì nó nhanh hơn filter.

Cập nhật:

Trong Swift 4.2+, bạn có thể xóa một hoặc nhiều lần xuất hiện betavới removeAll(where:):

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

34
Đây là câu trả lời tốt nhất, nhưng thật ngu ngốc nếu không có một loại bỏ (đối tượng: "beta").
zeeple

5
Tôi nghĩ .index(of: chỉ có sẵn nếu bộ sưu tập chứa Equatablecác loại.
Adam Waite

@AdamWaite Có nhưng điều này cũng áp dụng cho các loại Foundation.
vadian 17/09/17

Điều này không đúng, nếu bạn có nhiều hơn một "bản beta" thì sao? Điều này chỉ hoạt động nếu mảng không chứa nhiều hơn một lần xuất hiện. Câu trả lời đúng là sử dụng một bộ lọc hoặc chạy câu trả lời này trong một thời gian,while let index = array.index(of: "beta") { array.remove(at: index) }
juancazalla

@juancazalla Bạn đúng nhưng trong trường hợp nếu mảng có thể chứa nhiều hơn một lần xuất hiện, hãy sử dụng filtergiải pháp. Nhưng nếu các đối tượng là duy nhất luôn sử dụng index(ofvì nó hoạt động hiệu quả hơn nhiều so vớifilter
vadian 31/05

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

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

7
Đó là giải pháp Swift chính xác, sử dụng các tính năng cú pháp được cung cấp bởi ngôn ngữ.
Michael

1
Nếu mục là một đối tượng thì sao?
TomSawyer

@TomSawyer để lọc ra một đối tượng, sử dụng $ 0 ==!
Mike Taverne

25

Đối với Swift 3, bạn có thể sử dụng chỉ mục (where :) và bao gồm một bao đóng để so sánh một đối tượng trong mảng ($ 0) với bất kỳ thứ gì bạn đang tìm kiếm.

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

Điều này sẽ hoạt động nếu tôi muốn xóa nhiều đối tượng? như (trong đó: {$ 0 == "beta" || $ 0 == "gamma"})
Irshad Mohamed

16

Một giải pháp hay và hữu ích khác là tạo loại tiện ích mở rộng này:

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
    }

}

Theo cách này, nếu bạn có mảng của mình với các đối tượng tùy chỉnh:

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
Điều này chỉ hoạt động nếu mảng không chứa nhiều hơn một lần xuất hiện. Câu trả lời đúng là sử dụng bộ lọc hoặc chạy câu trả lời này trong một thời gian. Là một người sử dụng phần mở rộng này, tôi hy vọng nó sẽ loại bỏ tất cả các lần xuất hiện và không chỉ có một
juancazalla

Nó hay, nhưng nó phải là remove(element: Element)vì trong Array bạn cũng có thể lưu trữ các kiểu như Int, Double - chúng không phải là đối tượng.
Radek Wilczak

8

Trong Swift 5 , sử dụng cái này Extension:

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

thí dụ:

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

Trong Swift 3 , sử dụng cái này Extension:

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

thí dụ:

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

6
  1. for var index = self.indexOfObject(object); index != NSNotFound; index = self.indexOfObject(object) là vòng lặp for theo kiểu C và đã bị xóa

  2. Thay đổi mã của bạn thành một cái gì đó như thế này để loại bỏ tất cả các đối tượng tương tự nếu nó đã lặp lại:

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

liệt kê -> bộ lọc -> bản đồ và loại bỏ (tại) là giải pháp thông minh. Đề xuất cái này
Ryan X

4

Swift 4

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

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

3

Giải pháp một dòng chính xác và hiệu quả để xóa một đối tượng duy nhất (có tên là "objectToRemove") khỏi một mảng các đối tượng này (có tên "array") trong Swift 3 là:

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

1

Hãy thử điều này trong Swift 3

array.remove(at: Index)

Thay vì

array.removeAtIndex(index)

Cập nhật

"Declaration is only valid at file scope".

Đảm bảo rằng đối tượng nằm trong phạm vi. Bạn có thể cho phạm vi là "nội bộ", là phạm vi mặc định.

index(of:<Object>) để làm việc, lớp học phải tuân theo Equatable


1

Trong Swift 3 và 4

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

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

Từ Swift 4.2, bạn có thể sử dụng phương pháp nâng cao hơn (nhanh hơn và tiết kiệm bộ nhớ)

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

thay vì

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

Đọc thêm tại đây


1

Phần mở rộng cho mảng để làm điều đó dễ dàng và cho phép chuỗi Swift 4.2 trở lên:

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

Nhãn tranh cãi '(nơi :)' không phù hợp với bất kỳ quá tải sẵn
jeet.chanchawat

1
@ jeet.chanchawat chắc hẳn là phiên bản nhanh khác ... Ồ câu hỏi này dành cho 3 người? Vâng, tôi nghĩ rằng tôi đã 4.2 tại thời điểm viết bài nhưng không nhớ bây giờ, sẽ kiểm tra nó sau này, nó chắc chắn làm việc cho tôi
Renetik

0

Đây là câu trả lời chính thức để tìm chỉ mục của đối tượng cụ thể, sau đó bạn có thể dễ dàng xóa bất kỳ đối tượng nào bằng chỉ mục đó:

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

Đây là liên kết: https://developer.apple.com/documentation/swift/array/2994720-firstindex


0

Đây là những gì tôi đã sử dụng (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)

Các kết quả:

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

Quan trọng: Mảng mà bạn xóa các mục phải chứa các phần tử có thể lập được (chẳng hạn như đối tượng, chuỗi, số, v.v.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.