Swift
Arrays
Programming
Swift Tips
Coding

How do I check in Swift if two arrays contain the same elements regardless of the order in which those elements appear in?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Two Swift arrays can contain the same values while still comparing unequal, because array equality is order-sensitive. If you want to ignore order, you need to compare them as multisets, meaning the values must match and the number of occurrences of each value must match too.

Sort Both Arrays When Elements Are Comparable

The simplest solution is to sort both arrays and compare the results. This works well when the element type conforms to Comparable.

swift
1let first = [3, 1, 2, 2]
2let second = [2, 3, 2, 1]
3
4let same = first.sorted() == second.sorted()
5print(same) // true

This is concise and easy to read. It also handles duplicates correctly because both sorted arrays must have the same values in the same counts after sorting.

A reusable generic helper looks like this:

swift
1func haveSameElementsIgnoringOrder<T: Comparable>(
2    _ lhs: [T],
3    _ rhs: [T]
4) -> Bool {
5    lhs.sorted() == rhs.sorted()
6}
7
8print(haveSameElementsIgnoringOrder([1, 2, 2], [2, 1, 2])) // true
9print(haveSameElementsIgnoringOrder([1, 2, 2], [1, 2]))    // false

The tradeoff is cost. Sorting is O(n log n), which is fine for many application-level checks but not always ideal for very large arrays.

Use Frequency Counting When Elements Are Hashable

If the values are Hashable, a counting dictionary avoids sorting and usually reads closer to the real intent. You count how many times each value appears in each array, then compare the two dictionaries.

swift
1func haveSameMultiset<T: Hashable>(
2    _ lhs: [T],
3    _ rhs: [T]
4) -> Bool {
5    guard lhs.count == rhs.count else { return false }
6
7    var counts: [T: Int] = [:]
8
9    for item in lhs {
10        counts[item, default: 0] += 1
11    }
12
13    for item in rhs {
14        guard let current = counts[item] else { return false }
15
16        if current == 1 {
17            counts.removeValue(forKey: item)
18        } else {
19            counts[item] = current - 1
20        }
21    }
22
23    return counts.isEmpty
24}
25
26print(haveSameMultiset(["a", "b", "b"], ["b", "a", "b"])) // true
27print(haveSameMultiset(["a", "b", "b"], ["a", "b", "c"])) // false

This approach is often the best general solution because it preserves duplicate counts and runs in roughly linear time for normal hash table behavior.

Why Set Alone Is Not Enough

A common mistake is to convert both arrays to sets and compare the sets:

swift
1let a = [1, 2, 2]
2let b = [1, 1, 2]
3
4print(Set(a) == Set(b)) // true, but the arrays are not equivalent

This fails because a set removes duplicates. If your requirement is “same unique values,” then Set is correct. If your requirement is “same elements with the same counts,” then Set is incomplete.

Choosing the Right Approach

Use sorting when:

  • the element type is already Comparable
  • readability matters more than micro-optimizing
  • the arrays are not large enough for sorting cost to matter

Use frequency counting when:

  • duplicates must be preserved
  • the element type is Hashable
  • you want a more scalable check for larger inputs

For custom model types, conforming to Hashable usually makes the dictionary-count approach straightforward:

swift
1struct User: Hashable {
2    let id: Int
3    let name: String
4}
5
6let teamA = [
7    User(id: 1, name: "Ana"),
8    User(id: 2, name: "Bo"),
9]
10
11let teamB = [
12    User(id: 2, name: "Bo"),
13    User(id: 1, name: "Ana"),
14]
15
16print(haveSameMultiset(teamA, teamB)) // true

Common Pitfalls

The biggest pitfall is using Set when duplicates matter. Arrays such as [1, 1, 2] and [1, 2, 2] collapse to the same set even though they are not equivalent multisets.

Another pitfall is forgetting the type constraints. Sorting requires Comparable, while dictionary counting requires Hashable. If your type has neither, you need to define a different comparison strategy.

Floating-point arrays deserve extra care. Values such as Double.nan do not behave like ordinary numbers in equality checks, so any generic comparison may surprise you if NaN is possible in the data.

Also consider whether order truly does not matter. If the arrays represent user actions, execution steps, or time-series samples, ignoring order may hide meaningful differences.

Summary

  • Plain array equality in Swift is order-sensitive.
  • Sorting both arrays is the simplest fix when elements are Comparable.
  • Counting occurrences in a dictionary is a strong choice when elements are Hashable.
  • 'Set comparison only works when duplicate counts do not matter.'
  • Pick the strategy that matches both your data type and your definition of “same.”

Course illustration
Course illustration

All Rights Reserved.