Swift
merge arrays
sorted arrays
Swift programming
coding tutorial

How to merge two sorted arrays in Swift?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

When both input arrays are already sorted, you should not sort everything again after concatenation. The efficient solution is a two-pointer merge, which walks both arrays once and produces a sorted result in linear time.

Use the standard two-pointer algorithm

The idea is simple: keep one index for each array, compare the current elements, append the smaller one, and advance only that index.

swift
1func mergeSorted(_ left: [Int], _ right: [Int]) -> [Int] {
2    var result: [Int] = []
3    result.reserveCapacity(left.count + right.count)
4
5    var i = 0
6    var j = 0
7
8    while i < left.count && j < right.count {
9        if left[i] <= right[j] {
10            result.append(left[i])
11            i += 1
12        } else {
13            result.append(right[j])
14            j += 1
15        }
16    }
17
18    while i < left.count {
19        result.append(left[i])
20        i += 1
21    }
22
23    while j < right.count {
24        result.append(right[j])
25        j += 1
26    }
27
28    return result
29}
30
31let a = [1, 4, 7, 10]
32let b = [2, 3, 8, 12]
33print(mergeSorted(a, b))

This runs in O(n + m) time because each element is inspected once. The extra space is also O(n + m) because the merged array stores every element from both inputs.

reserveCapacity is worth keeping. It avoids repeated reallocation while the result grows, which is a small but real performance improvement in Swift.

Make it generic for any comparable type

If you want the same logic for strings, dates, or custom comparable models, make the function generic:

swift
1func mergeSorted<T: Comparable>(_ left: [T], _ right: [T]) -> [T] {
2    var result: [T] = []
3    result.reserveCapacity(left.count + right.count)
4
5    var i = 0
6    var j = 0
7
8    while i < left.count && j < right.count {
9        if left[i] <= right[j] {
10            result.append(left[i])
11            i += 1
12        } else {
13            result.append(right[j])
14            j += 1
15        }
16    }
17
18    result.append(contentsOf: left[i...])
19    result.append(contentsOf: right[j...])
20    return result
21}
22
23print(mergeSorted(["apple", "pear"], ["banana", "orange"]))

This version works because Comparable guarantees the ordering operators needed for the merge. It is a good default when you want reusable utility code in a Swift project.

If you own the destination buffer

Some interview problems give you a first array with spare capacity and ask for an in-place merge. In that case, fill from the end so you do not overwrite values you still need:

swift
1func mergeIntoFirst(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
2    var i = m - 1
3    var j = n - 1
4    var writeIndex = m + n - 1
5
6    while j >= 0 {
7        if i >= 0 && nums1[i] > nums2[j] {
8            nums1[writeIndex] = nums1[i]
9            i -= 1
10        } else {
11            nums1[writeIndex] = nums2[j]
12            j -= 1
13        }
14        writeIndex -= 1
15    }
16}
17
18var nums1 = [1, 3, 5, 0, 0, 0]
19let nums2 = [2, 4, 6]
20mergeIntoFirst(&nums1, 3, nums2, 3)
21print(nums1)

This variant is still linear, but it avoids allocating a second result array because it reuses the storage you already have.

Why concatenating and sorting is usually worse

You might see code like this:

swift
let merged = (left + right).sorted()

It is concise, and for tiny arrays it may be completely fine. The tradeoff is that it throws away the fact that both inputs are already sorted. Sorting the combined result costs more work than a merge, so the two-pointer version scales much better as the arrays grow.

In performance-sensitive code, use the structure you already know about the inputs instead of asking the sort algorithm to rediscover it.

Common Pitfalls

The most common bug is forgetting to append the remaining tail after one array runs out. That silently drops values.

Another mistake is assuming the inputs are sorted without checking the contract. If either array is unsorted, the merged result will also be wrong even though the code looks correct.

Off-by-one errors are also common in the in-place version, especially when one array is empty. Test edge cases such as two empty arrays, one empty array, duplicates, and arrays of different lengths.

Finally, do not optimize prematurely by replacing clear code with tricky index math unless you have measured a real problem. The standard merge is already efficient and easy to maintain.

Summary

  • Use a two-pointer merge to combine two sorted arrays in linear time.
  • Reserve result capacity in Swift to reduce reallocations.
  • Prefer a generic T: Comparable version when the utility should work with more than Int.
  • Use the back-to-front in-place technique only when you already have destination buffer space.
  • Avoid concatenating and sorting unless the arrays are tiny and simplicity matters more than performance.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.