let combined = arrayA + arrayB. To append elements directly into an existing mutable array without allocating a third array, call arrayA.append(contentsOf: arrayB) or use the compound assignment operator arrayA += arrayB.Why this happens
In Swift, Array is a struct backed by value semantics and copy-on-write memory management. Unlike languages where arrays are mutable reference types by default, Swift requires explicit decisions about mutability and memory allocation when joining collections.
Because Swift arrays are strongly typed (Array<Element>), merging two collections requires both sequences to share an identical element type or to be explicitly mapped to a common parent type or protocol. Attempting to concatenate incompatible types causes compiler errors like Cannot convert value of type... or Binary operator '+' cannot be applied to operands.
Depending on whether you need a brand-new array or want to modify an existing buffer in place, Swift provides distinct operators and methods. Choosing the wrong approach can lead to unnecessary memory copies, unexpected mutations, or high algorithmic complexity in performance-critical loops.
How to fix it
1. Create a new merged array using the + operator
When you have two immutable (let) arrays or want to preserve both original collections without side effects, use the generic addition operator +(_:_:) defined on Array.
let firstBatch: [Int] = [1, 2, 3]
let secondBatch: [Int] = [4, 5, 6]
// Allocates a new array containing elements from both
let combinedBatch = firstBatch + secondBatch
print(combinedBatch) // [1, 2, 3, 4, 5, 6]
The + operator accepts any right-hand collection conforming to Sequence as long as its Element matches the left-hand array’s Element. This means you can add a Set or an ArraySlice directly to an Array:
let numbers = [10, 20, 30]
let additionalSet: Set<Int> = [40, 50]
let allNumbers = numbers + additionalSet
print(allNumbers) // [10, 20, 30, 40, 50] (order of Set elements may vary)
2. Append in place using append(contentsOf:)
If the destination array is declared with var, appending elements directly avoids allocating an entirely separate buffer for the result. The standard library provides append(contentsOf:) for this purpose.
var activeUsers = ["Alice", "Bob"]
let pendingUsers = ["Charlie", "Diana"]
activeUsers.append(contentsOf: pendingUsers)
print(activeUsers) // ["Alice", "Bob", "Charlie", "Diana"]
If you know in advance how many total items will be merged, call reserveCapacity(_:) first to prevent intermediate buffer reallocations:
var results: [Double] = [1.5, 2.5]
let incomingData: [Double] = [3.5, 4.5, 5.5]
results.reserveCapacity(results.count + incomingData.count)
results.append(contentsOf: incomingData)
3. Use the compound assignment operator +=
Swift defines += for RangeReplaceableCollection, providing shorthand syntax for append(contentsOf:). It mutates the left-hand array in place.
var scores: [Int] = [95, 88, 72]
let bonusScores: [Int] = [100, 84]
scores += bonusScores
print(scores) // [95, 88, 72, 100, 84]
Like +, the right-hand operand can be any Sequence with identical elements:
var identifiers: [String] = ["id_01"]
identifiers += ["id_02", "id_03"]
Keep in mind that chaining multiple += operations inside tight rendering loops without reserving capacity can trigger repeated heap reallocations as the underlying contiguous storage doubles in size.
4. Flatten multiple arrays with joined() or flatMap
When combining three or more arrays (or an array of arrays), avoid chaining + operators, such as arr1 + arr2 + arr3 + arr4. Chaining creates temporary arrays at every addition step, producing $O(N^2)$ copying overhead.
Instead, place the arrays in a collection and call joined():
let groupA = [1, 2]
let groupB = [3, 4]
let groupC = [5, 6]
// Efficient lazy flattening converted back to an Array
let allGroups = Array([groupA, groupB, groupC].joined())
print(allGroups) // [1, 2, 3, 4, 5, 6]
If you are transforming elements while merging an array of arrays, flatMap flattens the hierarchy in a single pass:
let nestedSections: [[String]] = [
["Header", "Subheader"],
["Body Row 1", "Body Row 2"],
["Footer"]
]
let linearItems = nestedSections.flatMap { $0 }
print(linearItems) // ["Header", "Subheader", "Body Row 1", "Body Row 2", "Footer"]
5. Merge heterogeneous arrays with a common protocol or Any
If the two arrays do not share the exact same concrete type, Swift’s type checker rejects + and append(contentsOf:). You must explicitly specify a common type.
For numeric types (such as [Int] and [Double]), convert one array before merging:
let integers: [Int] = [1, 2, 3]
let doubles: [Double] = [4.5, 5.5]
// Convert Ints to Double before merging
let mergedDoubles: [Double] = integers.map(Double.init) + doubles
print(mergedDoubles) // [1.0, 2.0, 3.0, 4.5, 5.5]
For unrelated types, bridge them using an explicit protocol or an Any array:
let strings: [String] = ["One", "Two"]
let numbers: [Int] = [3, 4]
let mixed: [Any] = (strings as [Any]) + (numbers as [Any])
How to prevent it
- Favor
append(contentsOf:)over+for mutable state: When building an array incrementally, modifying an existingvarin place avoids unnecessary allocations of intermediate arrays. - Avoid chained
+operations: Replacea + b + c + dwithArray([a, b, c, d].joined())to prevent redundant copies and intermediate garbage collection. - Call
reserveCapacityon large merges: If merging thousands of elements into an existing array, reserve the combined count first to prevent repeated memory reallocations. - Verify matching element types early: Ensure elements conform to the same type or bridge them with
.map()before passing them to concatenation operators.
FAQ
What is the performance difference between + and append(contentsOf:)?
The + operator allocates a brand-new array and copies all elements from both source sequences into it, requiring memory proportional to the total count. In contrast, append(contentsOf:) appends items directly to an existing mutable buffer, reusing available capacity and avoiding an extra collection allocation.
Can I merge two arrays and remove duplicates at the same time?
Yes, if the element type conforms to Hashable. Convert the merged result to a Set and back to an Array using Array(Set(a + b)), or use an OrderedSet if you need to retain the original insertion order.
Why does array1 + array2 fail with “Cannot convert value of type”?
Swift requires both arrays to share an identical Element type. If one array contains Int and the other contains Double, or if one contains optional values ([String?]) and the other non-optionals ([String]), you must cast or map the elements to a matching type before concatenating.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
