Find every other element in an array with Swift
Published on: June 30, 2015There 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
.