316

How can I unset/remove an element from an array in Apple's new language Swift?

Here's some code:

let animals = ["cats", "dogs", "chimps", "moose"]

How could the element animals[2] be removed from the array?

overactor
  • 1,759
  • 2
  • 15
  • 23
Leopold Joy
  • 4,524
  • 4
  • 28
  • 37

18 Answers18

410

The let keyword is for declaring constants that can't be changed. If you want to modify a variable you should use var instead, e.g:

var animals = ["cats", "dogs", "chimps", "moose"]

animals.remove(at: 2)  //["cats", "dogs", "moose"]

A non-mutating alternative that will keep the original collection unchanged is to use filter to create a new collection without the elements you want removed, e.g:

let pets = animals.filter { $0 != "chimps" }
mythz
  • 141,670
  • 29
  • 246
  • 390
284

Given

var animals = ["cats", "dogs", "chimps", "moose"]

Remove first element

animals.removeFirst() // "cats"
print(animals)        // ["dogs", "chimps", "moose"]

Remove last element

animals.removeLast() // "moose"
print(animals)       // ["cats", "dogs", "chimps"]

Remove element at index

animals.remove(at: 2) // "chimps"
print(animals)           // ["cats", "dogs", "moose"]

Remove element of unknown index

For only one element

if let index = animals.firstIndex(of: "chimps") {
    animals.remove(at: index)
}
print(animals) // ["cats", "dogs", "moose"]

For multiple elements

var animals = ["cats", "dogs", "chimps", "moose", "chimps"]

animals = animals.filter(){$0 != "chimps"}
print(animals) // ["cats", "dogs", "moose"]

Notes

  • The above methods modify the array in place (except for filter) and return the element that was removed.
  • Swift Guide to Map Filter Reduce
  • If you don't want to modify the original array, you can use dropFirst or dropLast to create a new array.

Updated to Swift 5.2

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • Thanks for these examples, in you *Remove element of unknown index* > *for multiple elements*, what closure would you write to remove `chimps && moose` for instance? I am looking for something different than `{$0 != "chimps" && $0 != "moose"}` –  Feb 21 '17 at 10:02
  • why bother getting the index just to pass it in? animals.removeAll{ $0 == "chimps" } – theZ3r0CooL Feb 16 '22 at 18:40
206

The above answers seem to presume that you know the index of the element that you want to delete.

Often you know the reference to the object you want to delete in the array. (You iterated through your array and have found it, e.g.) In such cases it might be easier to work directly with the object reference without also having to pass its index everywhere. Hence, I suggest this solution. It uses the identity operator !==, which you use to test whether two object references both refer to the same object instance.

func delete(element: String) {
    list = list.filter { $0 != element }
}

Of course this doesn't just work for Strings.

zeeshan
  • 4,913
  • 1
  • 49
  • 58
Daniel
  • 3,758
  • 3
  • 22
  • 43
  • 32
    Should be `list = list.filter({ $0 != element })` – Craig Grummitt Sep 04 '15 at 18:09
  • 6
    Not if you want to check with the identity operator. – Daniel Sep 04 '15 at 18:12
  • 3
    `array.indexOf({ $0 == obj })` – jrc Oct 05 '15 at 23:43
  • 3
    Note if other objects reference `list` this deletion won't update the other array references since you're assigning a new array to `list`. Just a subtle implication if you delete from arrays with this approach. – Crashalot Jan 21 '16 at 02:30
  • @Crashalot "if other objects reference list this deletion won't update the other array references..." Is this because arrays in Swift are structs, am I correct? – Andrej May 21 '16 at 13:09
  • 2
    Functional programming paradigm relies on immutable objects. I.e., you don't change them. Instead, you create a new object. This is what delete, map, reduce, etc. does. list will be a newly created object. In the above code snippet I'm assigning back to list a newly created object. That works for me, because I design my code in a way that follows functional programming. – Daniel May 21 '16 at 16:21
  • This will remove every matching element not just a single one. Let theArray = ["A", "B", "C", "A"] let newArray = theArray.filter({$0 != "A"}) results in newArray == ["B", "C"] – Scooter Sep 20 '20 at 00:49
  • If you want to get index of all matching element let filteredIndices = items.enumerated().filter{ "YoutElement" == $0.element }.map{ $0.offset } – Rajneesh071 Feb 04 '21 at 11:55
  • 1
    don't need to surround your {} with () – theZ3r0CooL Feb 16 '22 at 18:41
67

Swift 5: Here is a cool and easy extension to remove elements in an array, without filtering :

   extension Array where Element: Equatable {

    // Remove first collection element that is equal to the given `object`:
    mutating func remove(object: Element) {
        guard let index = firstIndex(of: object) else {return}
        remove(at: index)
    }

}

Usage :

var myArray = ["cat", "barbecue", "pancake", "frog"]
let objectToRemove = "cat"

myArray.remove(object: objectToRemove) // ["barbecue", "pancake", "frog"]

Also works with other types, such as Int since Element is a generic type:

var myArray = [4, 8, 17, 6, 2]
let objectToRemove = 17

myArray.remove(object: objectToRemove) // [4, 8, 6, 2]
Maschina
  • 755
  • 7
  • 30
Skaal
  • 1,224
  • 12
  • 10
  • 1
    Interesting this Array where Element: Equatable part – Nicolas Manzini Nov 21 '17 at 01:29
  • 1
    Brilliant. Though it doesn't work if you start with a list of Protocols, as — Protocol type cannot conform to 'Equatable' because only concrete types can conform to protocols :-( – AW101 Aug 07 '19 at 14:24
  • I like this solution because it covers removal of elements that belong to an array of struct – Marcos Sep 09 '20 at 08:58
  • I was searching for Objective-C equivalent remove function. This answer best fit for that. Thank you. – Shihab Feb 03 '21 at 00:01
26

As of Xcode 10+, and according to the WWDC 2018 session 223, "Embracing Algorithms," a good method going forward will be mutating func removeAll(where predicate: (Element) throws -> Bool) rethrows

Apple's example:

var phrase = "The rain in Spain stays mainly in the plain."
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]

phrase.removeAll(where: { vowels.contains($0) })
// phrase == "Th rn n Spn stys mnly n th pln."

see Apple's Documentation

So in the OP's example, removing animals[2], "chimps":

var animals = ["cats", "dogs", "chimps", "moose"]
animals.removeAll(where: { $0 == "chimps" } )
// or animals.removeAll { $0 == "chimps" }

This method may be preferred because it scales well (linear vs quadratic), is readable and clean. Keep in mind that it only works in Xcode 10+, and as of writing this is in Beta.

davidrynn
  • 2,246
  • 22
  • 22
25

If you have array of custom Objects, you can search by specific property like this:

if let index = doctorsInArea.firstIndex(where: {$0.id == doctor.id}){
    doctorsInArea.remove(at: index)
}

or if you want to search by name for example

if let index = doctorsInArea.firstIndex(where: {$0.name == doctor.name}){
    doctorsInArea.remove(at: index)
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Atef
  • 2,872
  • 1
  • 36
  • 32
25

For Swift4:

list = list.filter{$0 != "your Value"}
  • 1
    This will remove every matching element not just a single one. Let theArray = ["A", "B", "C", "A"] let newArray = theArray.filter({$0 != "A"}) results in newArray == ["B", "C"] – Scooter Sep 20 '20 at 00:49
20

You could do that. First make sure Dog really exists in the array, then remove it. Add the for statement if you believe Dog may happens more than once on your array.

var animals = ["Dog", "Cat", "Mouse", "Dog"]
let animalToRemove = "Dog"

for object in animals {
    if object == animalToRemove {
        animals.remove(at: animals.firstIndex(of: animalToRemove)!)
    }
}

If you are sure Dog exits in the array and happened only once just do that:

animals.remove(at: animals.firstIndex(of: animalToRemove)!)

If you have both, strings and numbers

var array = [12, 23, "Dog", 78, 23]
let numberToRemove = 23
let animalToRemove = "Dog"

for object in array {

    if object is Int {
        // this will deal with integer. You can change to Float, Bool, etc...
        if object == numberToRemove {
        array.remove(at: array.firstIndex(of: numberToRemove)!)
        }
    }
    if object is String {
        // this will deal with strings
        if object == animalToRemove {
        array.remove(at: array.firstIndex(of: animalToRemove)!)
        }
    }
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
GuiSoySauce
  • 1,763
  • 3
  • 24
  • 37
19

If you don't know the index of the element that you want to remove, and the element is conform the Equatable protocol, you can do:

animals.remove(at: animals.firstIndex(of: "dogs")!)

See Equatable protocol answer:How do I do indexOfObject or a proper containsObject

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Byron
  • 411
  • 5
  • 5
16

Few Operation relates to Array in Swift

Create Array

var stringArray = ["One", "Two", "Three", "Four"]

Add Object in Array

stringArray = stringArray + ["Five"]

Get Value from Index object

let x = stringArray[1]

Append Object

stringArray.append("At last position")

Insert Object at Index

stringArray.insert("Going", at: 1)

Remove Object

stringArray.remove(at: 3)

Concat Object value

var string = "Concate Two object of Array \(stringArray[1]) + \(stringArray[2])"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Solid Soft
  • 1,872
  • 2
  • 25
  • 55
11

Remove elements using indexes array:

  1. Array of Strings and indexes

    let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
    let indexAnimals = [0, 3, 4]
    let arrayRemainingAnimals = animals
        .enumerated()
        .filter { !indexAnimals.contains($0.offset) }
        .map { $0.element }
    
    print(arrayRemainingAnimals)
    
    //result - ["dogs", "chimps", "cow"]
    
  2. Array of Integers and indexes

    var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    let indexesToRemove = [3, 5, 8, 12]
    
    numbers = numbers
        .enumerated()
        .filter { !indexesToRemove.contains($0.offset) }
        .map { $0.element }
    
    print(numbers)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
    



Remove elements using element value of another array

  1. Arrays of integers

    let arrayResult = numbers.filter { element in
        return !indexesToRemove.contains(element)
    }
    print(arrayResult)
    
    //result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
    
  2. Arrays of strings

    let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
    let arrayRemoveLetters = ["a", "e", "g", "h"]
    let arrayRemainingLetters = arrayLetters.filter {
        !arrayRemoveLetters.contains($0)
    }
    
    print(arrayRemainingLetters)
    
    //result - ["b", "c", "d", "f", "i"]
    
Krunal
  • 77,632
  • 48
  • 245
  • 261
  • 4
    This is one liner answer and it is much efficient for better coding and fast execution. – The iOSDev Oct 24 '17 at 11:31
  • Hi @Krunal - great answer, could you take a look at the following question (releasing images from an image array): https://stackoverflow.com/questions/47735975/how-to-release-images-from-an-image-array-in-swift – Server Programmer Dec 10 '17 at 17:37
9

I came up with the following extension that takes care of removing elements from an Array, assuming the elements in the Array implement Equatable:

extension Array where Element: Equatable {
  
  mutating func removeEqualItems(_ item: Element) {
    self = self.filter { (currentItem: Element) -> Bool in
      return currentItem != item
    }
  }

  mutating func removeFirstEqualItem(_ item: Element) {
    guard var currentItem = self.first else { return }
    var index = 0
    while currentItem != item {
      index += 1
      currentItem = self[index]
    }
    self.remove(at: index)
  }
  
}
  

Usage:

var test1 = [1, 2, 1, 2]
test1.removeEqualItems(2) // [1, 1]

var test2 = [1, 2, 1, 2]
test2.removeFirstEqualItem(2) // [1, 1, 2]
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
nburk
  • 22,409
  • 18
  • 87
  • 132
  • Hi @nburk - great answer, could you take a look at the following question (releasing images from an image array): https://stackoverflow.com/questions/47735975/how-to-release-images-from-an-image-array-in-swift – Server Programmer Dec 10 '17 at 17:37
  • This is cleanest solution. – JIANG Mar 22 '21 at 18:37
  • If the array does not contains the item, self[index] will fail in removeFirstEqualItem method. – Confused Feb 16 '23 at 10:10
7

Regarding @Suragch's Alternative to "Remove element of unknown index":

There is a more powerful version of "indexOf(element)" that will match on a predicate instead of the object itself. It goes by the same name but it called by myObjects.indexOf{$0.property = valueToMatch}. It returns the index of the first matching item found in myObjects array.

If the element is an object/struct, you may want to remove that element based on a value of one of its properties. Eg, you have a Car class having car.color property, and you want to remove the "red" car from your carsArray.

if let validIndex = (carsArray.indexOf{$0.color == UIColor.redColor()}) {
  carsArray.removeAtIndex(validIndex)
}

Foreseeably, you could rework this to remove "all" red cars by embedding the above if statement within a repeat/while loop, and attaching an else block to set a flag to "break" out of the loop.

ObjectiveTC
  • 2,477
  • 30
  • 22
7

Swift 5

guard let index = orders.firstIndex(of: videoID) else { return }
orders.remove(at: index)
Jerome
  • 2,114
  • 24
  • 24
4

This should do it (not tested):

animals[2...3] = []

Edit: and you need to make it a var, not a let, otherwise it's an immutable constant.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Analog File
  • 5,280
  • 20
  • 23
  • 5
    When using a (sub)range of an existing array to create another array the range needs to have 3 dots. The above should be written as animals[2...3] – zevij Jan 19 '16 at 10:33
  • `Array` conforms to `RangeReplaceableCollection` protocol and it provides a method exactly for this purpose `animals.removeSubrange(2...3)` – Leo Dabus Oct 06 '20 at 02:21
  • Just a note that the code in this answer removes two elements, the ones at the indexes 2 and 3. `2..<3.` can be used if wanting to remove only the element at index 2. – Cristik Nov 15 '20 at 14:39
2

extension to remove String object

extension Array {
    mutating func delete(element: String) {
        self = self.filter() { $0 as! String != element }
    }
}
Varun Naharia
  • 5,318
  • 10
  • 50
  • 84
2

I use this extension, almost same as Varun's, but this one (below) is all-purpose:

 extension Array where Element: Equatable  {
        mutating func delete(element: Iterator.Element) {
                self = self.filter{$0 != element }
        }
    }
Jsleshem
  • 715
  • 1
  • 10
  • 31
user3206558
  • 392
  • 1
  • 12
2

To remove elements from an array, use the remove(at:), removeLast() and removeAll().

yourArray = [1,2,3,4]

Remove the value at 2 position

yourArray.remove(at: 2)

Remove the last value from array

yourArray.removeLast()

Removes all members from the set

yourArray.removeAll()
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Ronak Patel
  • 609
  • 4
  • 16