Array removeFirst

Is it possible to do "get and remove first element of array" in one go?

var items: [String] = ...
....
var first: String?
if !items.isEmpty {
    first = items.removeFirst()
}

I don't think so, but if you need to call this function repeatedly, e.g. in parsing, you could perhaps first turn your array into an ArraySlice and then use .popFirst(). Since the slice keeps the underlying collection and only does simple bookkeeping of start and end indices, the function is super cheap.

var slice = items[...]
let first = slice.popFirst()
3 Likes

Did you try it? Your example pretty much works as is (see removeFirst()), though it is inefficient to do it this way rather than using slices as @sveinhal suggests (in particular, you are likely to create accidentally quadratic algorithms your way).

4 Likes

In this particular case of mine quadratic/cubic/etc behaviour is non issue (N is a very small number), my main concern is having to write the check and the operation separately (extra line count + non atomicity). I hoped there was a built-in operation to that account. I'm also missing "find and remove first element matching criteria". Simulating it now with:

var item: String?
if let index = items.firstIndex(where: { it in ... }) {
    item = items[index]
    items.remove(at: index)
}

Edit:

I realised I also need a version of removeFirst that passes both element and index in its predicate parameter. Doing this now:

extension Array {
    mutating func removeFirstElement2(where predicate: (Element, Int) -> Bool) -> Element? {
        for i in 0 ..< count {
            let element = self[i]
            if predicate(element, i) {
                remove(at: i)
                return element
            }
        }
        return nil
    }
}

Is there any better (e.g., more functional) way?

"removeFirst()" / "removeFirst(where:...)" calls returning Optional would be perfect.

One thing to watch out for with the removeX methods is that they don’t preserve indices:

var a = ["Hello", "Cruel", "World!"]
let i = a.firstIndex(of: "Cruel")!
a.removeFirst()
print(a[i]) // World!

Contrast:

let a = ["Hello", "Cruel", "World!"]
var aS = a[...]
let i = aS.firstIndex(of: "Cruel")!
aS.popFirst()
print(aS[i]) // Cruel

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

4 Likes