Find every other element in an array with Swift

Published on: June 30, 2015

Note:
This blog post has been updated for Xcode 11 and Swift 5 👍🏼

There are times when you need to extract a subset of an array. For example, you might need to find all elements in an array at an odd index. Or maybe you need all items at an even index. In other words, you're looking for every "other" element in an array. This might seem like a non-trivial task and you may have tried this before using a for loop as follows:

var itemsAtEvenIndices = [Int]()
let allItems = [1, 2, 3, 4, 5, 6, 7]

var index = 0
for item in allItems {
  if index % 2 == 0 {
    itemsAtEvenIndices.append(item)
  }
  index += 1
}

This isn't a bad approach, but we can do better. A slightly nicer way would be to use the enumerated() method that is defined on Sequence:

var itemsAtEvenIndices = [Int]()
let allItems = [1, 2, 3, 4, 5, 6, 7]

for (index, item) in allItems.enumerated() {
  if index.isMultiple(of: 2) {
    itemsAtEvenIndices.append(item)
  }
}

This works and saves you some bookkeeping because you don't have to increment the index in every iteration of the loop but you still have to define a mutable array that you append items to. Let's take a look at one last way to extract all items at even indices without any mutable arrays and without unneeded bookkeeping:

let allItems = [1, 2, 3, 4, 5, 6, 7]
let itemsAtEvenIndices = allItems.enumerated().compactMap { tuple in
  tuple.offset.isMultiple(of: 2) ? tuple.element : nil
}

The code above uses compactMap to transform tuples of (offset: Int, element: Int) into an array of [Int]. Since compactMap filters out all nil values and only keeps the Int values, we can use a ternary statement that checks whether tuple.offset.isMultiple(of: 2) is true. If it is, we return tuple.element and if it isn't, we return nil. The end result is the same as the previous two examples except it's cleaner and doesn't involve any mutable state, or intermediate variables.

If you want to learn more about compactMap, check out the following post I wrote: When to use map, flatMap and compactMap. If you have any questions, feedback, or just want to get in touch. Don't hesitate to reach out to me on Twitter.

Special thanks to Bas Broek for pointing out that tuple.offset.isMultiple(of: 2) is maybe a bit nicer than tuple.offset % 2 == 0.

Categories

Swift Tips

Subscribe to my newsletter