Удалить сопоставленный элемент из массива объектов?

У меня есть массив таких объектов:

var myArr = [
  MyObject(name: "Abc", description: "Lorem ipsum 1."),
  MyObject(name: "Def", description: "Lorem ipsum 2."),
  MyObject(name: "Xyz", description: "Lorem ipsum 3.")
]

Я знаю, что могу найти подобранный элемент следующим образом:

var temp = myArr.filter { $0.name == "Def" }.first

Но как удалить его из оригинала myArr? Я надеялся, что filter.first может каким-то образом вернуть индекс, чтобы я мог использовать removeAtIndex. Или еще лучше, я хотел бы сделать что-то вроде этого:

myArr.removeAll { $0.name == "Def" } // Pseudo

Любые идеи?

Ответ 1

Что вы не понимаете, так это то, что Array является структурой и, следовательно, является типом значений. Он не может быть мутирован на месте, каким может быть экземпляр класса. Таким образом, вы всегда будете создавать новый массив за кулисами, даже если вы расширите Array, чтобы написать мутирующий метод removeIf.

Таким образом, нет недостатка или потери общности при использовании filter и логического отрицания вашего условия закрытия:

myArr = myArr.filter { $0.name != "Def" }

Например, вы можете написать removeIf следующим образом:

extension Array {
    mutating func removeIf(closure:(T -> Bool)) {
        for (var ix = self.count - 1; ix >= 0; ix--) {
            if closure(self[ix]) {
                self.removeAtIndex(ix)
            }
        }
    }
}

И вы можете использовать его следующим образом:

myArr.removeIf {$0.name == "Def"}

Но на самом деле это большая жирная трата вашего времени. Здесь вы ничего не делаете, что filter еще не делает. Может показаться синтаксисом myArr.removeIf, что вы мутируете myArr на месте, но вы не являетесь; вы заменяете его другим массивом. В самом деле, каждый вызов removeAtIndex в этом цикле создает другой массив! Поэтому вы можете использовать filter и быть счастливым.

Ответ 2

Получите объекты, используя фильтр, затем пройдите через массив и используйте myArr.removeAtIndex(index), чтобы удалить каждый объект. Использование фильтра делает именно это. Чтобы понять, что происходит, читайте ниже. Матт-ответ - это гораздо более простой способ сделать это, поскольку вы тестируете противоположное соответствие, поэтому каждый объект сохраняется, если он не соответствует вашему значению.

Прокрутите массив temp filter

if let index = find(temp, note) {
   myArr.removeAtIndex(index)
}

Ответ 3

если вы хотите удалить объект из массива, который выполняется итерацией, вы всегда должны перебирать назад, так как иначе вы в какой-то момент будете работать с уже недействующими индексами.

var myArr = [
    ["key":"value1"],
    ["key":"value2"],
    ["key":"value3"]
]

for index in stride(from: myArr.count - 1 , to: 0, by: -1){
    let x = myArr[index]
    if x["key"] == "value2"{
        myArr.removeAtIndex(index)
    }
}