2015-04-16 2 views
5

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

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 

Любые идеи?

+2

Что случилось с 'myArr = myArr.filter {$ 0.name! =" Def "}'? – matt

+0

Потому что это заставляет меня создавать новую переменную. Я хочу изменить существующую переменную 'myArr'. – TruMan1

+0

Нет, нет. 'myArr' все еще' myArr'. И это тип значения; вы не можете мутировать его на месте! Вы всегда будете создавать новый массив, даже если вы напишете мутирующий метод 'removeAll'. – matt

ответ

11

То, что вы не захватывая в том, что массив является структурой и, следовательно, является типом значения. Он не может быть мутирован на месте, каким может быть экземпляр класса. Таким образом, вы всегда будете создавать новый массив за кулисами, даже если вы расширите 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 и быть счастливым.

+0

Это правильный ответ. Если вы хотите понять, как это работает, посмотрите на мои. Понимание этого имеет жизненно важное значение для того, как фильтр и что более важно! = Работает. Это просто говорит: «Оставьте все объекты в этом массиве, если он не соответствует« Def ». –

+0

Я обновил свой ответ, чтобы показать фактическую реализацию 'removeIf'. Поэтому, если вы действительно этого хотите, вы можете расширить Array, чтобы иметь это как мутирующий метод. Но, как я также отмечаю, делать это было бы невероятно бессмысленно. – matt

+0

Does 'mutating func removeAtIndex()' действительно создать новый массив? –

1

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

Loop через темп фильтра массива

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

For-loop единственный способ найти индекс? .. Есть ли для этого элегантное закрытие? – TruMan1

+0

'find' работает только для простых массивов, а не массива объектов? Не удалось заставить 'find' работать с массивом объектов. – TruMan1

+0

Вы уже получаете все объекты, используя фильтр, тогда вы можете использовать find в цикле для удаления каждого из другого массива. –

1

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

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) 
    } 
} 
Смежные вопросы