Category

Swift: remove array item

Swift Language

Swift Array item removal without an index

The surprising contortions that you need to go through in order to remove an item from an array in Swift if you do not have its index in the array.

Introduction

I’m writing an app that uses standard music notation for input. Imagine a view with a staff and a tap inputs a note. Each “note view” represents a note model object. Then you decide that you do not want that note, so you need to delete it. You can get the note by pressing on it. Then that note needs to be deleted from a “notes array”.

So, you have the note, but not its index. If you had the index, Swift gives you zero trouble to remove it from the array.

But you don’t have the index. You have the item in the array. Well just use “indexOf”, right? Sure. Where is that? I couldn’t find anything like that. Let me know if you know of one.

What I ended up doing is removing the note by filtering the array. Here is a simple filter that removes the item.

One problem. I’m using a comparison operator. My class didn’t have one.

Table of Contents

Comparing objects

For that != operator to work, you need to implement the Equatable protocol. There is one requirement for this protocol: you provide an overload for the == operator at global scope. “Global scope” means outside of the class. When you overload the == operator, != will work too.

Like this:

Table of Contents

Summary

You can remove an item from an array by writing a filter closure. But, your item must implement the Equatable protocol.
If there is a simpler way to remove an item from an array without having its index, please let me know.

Update

Many people here and in the twitterverse have kindly pointed out there there is indeed an indexOf function. But it is not named anything close to that – it is the find(array, item) function.

<soapbox>
There is a lesson in this for API writers on naming. IMHO, it is poorly named. (Is there any ambiguity in the name “indexOf”? What are the chances that a polyglot programmer would seek a method/function named indexOf vs find?). I wonder how many people are going to have indexOf in an Array extension?
</soapbox>

My other problem was finding find. In neither the Array documentation nor the Collection documentation do I see this function. Is it unreasonable for me to be looking there?
Note that filter is defined as a global function and as an Array function.

Anyway, the actual definition is this:

Note that it is not array specific. You can do this with other Sequences.

So, the non filter version is this:

I haven’t yet looked to see which is more performant. My guess is the filter version. (but not if it were a linked list).

Again, thanks for the tip.

ps
to see the undocumented functions in Swift, do this:
Put this in your code:

Then Command-Click on Swift

Resources

8 thoughts on “Swift: remove array item”

  1. If there’ll only be one instance then you could use find(), like this:

    var arr = [1,2,3,4,5]
    if let ind = find(arr,4) {
    arr.removeAtIndex(ind)
    }

    and even repeat it multiple times, but I can’t think of a situation where you wouldn’t need Equatable, because the items in the array need to be compared to the thing you’re trying to find.

  2. and as for looking up documentation, have you tried the Command Click on the Class that you want to know more about? That is the most accurate and current documentation you can get, as it is generated from the system libraries/headers present on your system at the time.

    1. FWIW. cmd-click goes to the source, option-click is the documentation. I option-clicked on find to get the definition I quoted.
      The problem I had before was that find is not in a class, so there was nothing to click on. I didn’t know it existed. There still is no Apple list of the global functions in Swift. There is a blog post that lists them though.

  3. You can still use indexOfObject by bridging:

    class Midi {

    }

    var aMid = Midi()
    var bMid = Midi()

    var arrMid = [aMid,bMid]

    arrMid._bridgeToObjectiveC().indexOfObject(bMid)

    But for the maximum shelf-life, embracing Swift is most likely the wiser thing to do.

  4. I just came upon the following citation with The Swift Programming Language: Collection Types:

    If you need the integer index of each item as well as its value, use the global enumerate function to iterate over the array instead. The enumerate function returns a tuple for each item in the array composed of the index and the value for that item. You can decompose the tuple into temporary constants or variables as part of the iteration:

    for (index, value) in enumerate(shoppingList) {
    println(“Item \(index + 1): \(value)”)
    }
    // Item 1: Six eggs
    // Item 2: Milk
    // Item 3: Flour
    // Item 4: Baking Powder
    // Item 5: Bananas

  5. Swift has a ton of things that are overly contorted that are simple in C or C++. I think the String handling functions are overengineered and non-intuitive.

    1. Like the French word for Eighty.

      But then, I think Abe was onto something when he wrote “Four Score and seven years ago” rather than 87.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.