Removing object from array in Swift 3

118,001

Solution 1

The Swift equivalent to NSMutableArray's removeObject is:

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

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

if the objects are unique. There is no need at all to cast to NSArray and use indexOfObject:

The API index(of: also works but this causes an unnecessary implicit bridge cast to NSArray.

Of course you can write an extension of RangeReplaceableCollection to emulate the function. But due to value semantics you cannot name it removeObject.

extension RangeReplaceableCollection where Element : Equatable {
    @discardableResult
    mutating func remove(_ element : Element) -> Element?
    {
        if let index = firstIndex(of: element) {
            return remove(at: index)
        }
        return nil
    }
}

Like remove(at: it returns the removed item or nil if the array doesn't contain the item.


If there are multiple occurrences of the same object use filter. However in cases like data source arrays where an index is associated with a particular object firstIndex(of is preferable because it's faster than filter.

Update:

In Swift 4.2+ you can remove one or multiple occurrences of beta with removeAll(where:):

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

Solution 2

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

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

Solution 3

For Swift 3, you can use index(where:) and include a closure that does the comparison of an object in the array ($0) with whatever you are looking for.

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

Solution 4

Another nice and useful solution is to create this kind of extension:

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
    }

}

In this way, if you have your array with custom objects:

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) 

Solution 5

In Swift 5, Use this Extension:

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

example:

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

In Swift 3, Use this Extension:

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

example:

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

Related videos on Youtube

Kamlesh Shingarakhiya
Author by

Kamlesh Shingarakhiya

Updated on January 27, 2022

Comments

  • Kamlesh Shingarakhiya
    Kamlesh Shingarakhiya over 2 years

    In my application I added one object in array when select cell and unselect and remove object when re-select cell. I used that code but give me error.

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

    It gives me 2 error like that:

    C-style for statement has been removed in Swift 3
    Value of type '[Any]' has no member 'removeObject'
    
    • Paulw11
      Paulw11 over 7 years
      You can use a Set<Contact> rather than an Array. Can you provide more information about your contact object? If you have made it yourself you will need it to conform to Hashable and Equatable in order to put it in a set
  • zeeple
    zeeple about 7 years
    This is the best answer, but it is beyond stupid not to have a remove(object: "beta").
  • Ryan X
    Ryan X about 7 years
    enumerated -> filter -> map and remove(at) is smart solution. Recommend this one
  • Michael
    Michael almost 7 years
    That is the correct Swift solution, that makes use of syntax goodies offered by the language.
  • Adam Waite
    Adam Waite over 6 years
    I think .index(of: is only available if the collection contains Equatable types.
  • vadian
    vadian over 6 years
    @AdamWaite Yes but this applies also to the Foundation types.
  • Irshad Mohamed
    Irshad Mohamed over 6 years
    will this work if I want to remove multiple objects? like (where: {$0 == "beta" || $0 == "gamma" })
  • juancazalla
    juancazalla almost 6 years
    This isn't right, what if you have more than one "beta"? This only works if the array does not contain more than one occurrences. The right answer is using a filter or running this answer in a while, while let index = array.index(of: "beta") { array.remove(at: index) }
  • vadian
    vadian almost 6 years
    @juancazalla You are right but in the case if the array can contain more than one occurrence use the filter solution. But if the objects are unique use always index(of because it's much more performant than filter
  • juancazalla
    juancazalla almost 6 years
    This only works if the array does not contain more than one occurrences. The right answer is using a filter or running this answer in a while. As a user of this extension, I expect it to remove all the occurrences and not only one
  • Radek Wilczak
    Radek Wilczak over 5 years
    It's nice, but it should be remove(element: Element) because in Array you can store also types like Int, Double - they are not objects.
  • bibscy
    bibscy over 5 years
    @vadian I've read that you are a musician too and I was wondering if you could help me out with an answer stackoverflow.com/questions/53349969 . Many thanks
  • TomSawyer
    TomSawyer about 5 years
    What if item is an object?
  • jeet.chanchawat
    jeet.chanchawat about 5 years
    Argument labels '(where:)' do not match any available overloads
  • Renetik
    Renetik about 5 years
    @jeet.chanchawat well probably different swift version then ... Oh this question was for 3 ? Well I think I had 4.2 at time of writing but don't remember now, will check it later, it definitely worked for me
  • Mike Taverne
    Mike Taverne over 4 years
    @TomSawyer to filter out an object, use $0 !==