Reputation: 2678
I have this code:
let items = [1, 2, 3]
let sep = 0
I want to insert sep
between every two elements of items
to get a result similar to this:
newItems = [1, 0, 2, 0, 3]
Is there a concise way to do this through functional programming in Swift? Something similar to String.join()
, but for arrays.
Upvotes: 22
Views: 7297
Reputation: 2481
converted to swift 5
extension Array {
func insert(separator: Element) -> [Element] {
(0 ..< 2 * count - 1).map { $0 % 2 == 0 ? self[$0/2] : separator }
}
}
Upvotes: 10
Reputation: 539965
(Note: The answer has been updated for Swift 3 and later with the help of Brandon's answer and ober's answer).
This does the trick:
let items = [1, 2, 3]
let sep = 0
let newItems = Array(items.map { [$0] }.joined(separator: [sep]))
print(newItems) // [1, 0, 2, 0, 3]
items.map { [ $0 ] }
creates an array of single-element arrays, and joined(separator: [sep])
then interposes the separator and concatenates
the elements. The result is a JoinedSequence
from which we can create an Array
.
As it turns out (benchmarks below) it is quite expensive to create many temporary arrays. This can be avoided by using “single-element collections”:
let newItems = Array(items.map(CollectionOfOne.init).joined(separator: CollectionOfOne(sep)))
Another possible solution is
let newItems = (0 ..< 2 * items.count - 1).map { $0 % 2 == 0 ? items[$0/2] : sep }
which maps even indices to the corresponding element of items
,
and odd indices to the separator. This turns out to be the fastest solution for large arrays.
Benchmark: With items
containing 1,000,000 elements, compiled in Release mode on a 2.3 GHz Intel Core i7 MacBook Pro, I measured the following approximate execution times:
First method (map
+ joined
with arrays): 0.28 seconds.
Second method (map
+ joined
with CollectionOfOne
): 0.035 seconds.
Third method (using only map
): 0.015 seconds.
Upvotes: 38
Reputation: 769
Here is the original answer converted to Swift 3/4
let items = [1, 2, 3]
let sep = 0
let newItems = Array(items.map { [$0] }.joined(separator: [sep]))
print(newItems) // [1, 0, 2, 0, 3]
Upvotes: 8