Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Let's say there are two arrays...

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a"]

I'd like the result of the comparison of these two arrays to be true, and the following...

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a", "d"]

...to be false. How can I achieve that in Swift? I tried to convert both arrays to sets but for some reason Set() keeps removing some (usually duplicated) objects that the array contains.

Any help would be appreciated.

like image 627
Gerwazy Sokołowski Avatar asked Apr 19 '16 09:04

Gerwazy Sokołowski


People also ask

How do you check if two arrays have the same elements in the same order?

To check if two arrays have the same elements: Use the every() to check if the arrays contain the same element at the same index. The every method only returns true if the condition is met for all array elements.

How do I compare two array elements in Swift?

To check if two arrays are equal in Swift, use Equal To == operator. Equal To operator returns a Boolean value indicating whether two arrays contain the same elements in the same order. If two arrays are equal, then the operator returns true , or else it returns false .


8 Answers

Swift 3, 4

extension Array where Element: Comparable {
    func containsSameElements(as other: [Element]) -> Bool {
        return self.count == other.count && self.sorted() == other.sorted()
    }
}

// usage
let a: [Int] = [1, 2, 3, 3, 3]
let b: [Int] = [1, 3, 3, 3, 2]
let c: [Int] = [1, 2, 2, 3, 3, 3]

print(a.containsSameElements(as: b)) // true
print(a.containsSameElements(as: c)) // false

like image 160
Alexander Doloz Avatar answered Sep 29 '22 02:09

Alexander Doloz


you can do something like this:

  array1.sortInPlace()
  array2.sortInPlace()

  print(array1,array2)

  if array1 == array2 {
    print("equal")
  } else {
  print("not equal") 
  }

and if don't want change origional array we can do

 let sorted1 = array1.sort()
 let sorted2 = array2.sort()

  if sorted1 == sorted2 {
    print("equal")
  }else {
    print("not equal")
  }
like image 45
Sahil Avatar answered Oct 03 '22 02:10

Sahil


Using Set

let array1 = ["a", "b", "c"]
let array2 = ["b", "c", "a", "c"]

let set1 = Set(array1)
let set2 = Set(array2)

if (set1.count == set2.count && set1 == set2) { //if you compare big sets it is recommended to compare the count of items in the sets beforehand
    //they are identical
}

The Set implements Hashable so the task is to implement the hash function to work with a Set

like image 28
yoAlex5 Avatar answered Oct 01 '22 02:10

yoAlex5


Swift 5.2 Solution

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a"]

if array1.sorted() == array2.sorted() {
    print("array 1 & array 2 are same")
}
like image 40
Praveen Avatar answered Oct 01 '22 02:10

Praveen


I know this question is old, and it also didn't want to determine if array1 was a subset of array2. However, This works in Swift 5.3 and Xcode 12.3:

var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a", "d"]

print("array1 == array2? \(Set(array1) == Set(array2))")
print("array1 subset to array2? \(Set(array1).isSubset(of: Set(array2)))")
like image 37
SouthernYankee65 Avatar answered Sep 29 '22 02:09

SouthernYankee65


Create function to compare them:

func containSameElements(var firstArray firstArray: [String], var secondArray: [String]) -> Bool {
    if firstArray.count != secondArray.count {
        return false
    } else {
        firstArray.sortInPlace()
        secondArray.sortInPlace()
        return firstArray == secondArray
    }
}

Then:

var array1 = ["a", "a", "b"]
var array2 = ["a", "b", "a"]

var array3 = ["a", "b", "c"]
var array4 = ["b", "c", "a", "d"]

print(containSameElements(firstArray: array1, secondArray: array2)) //true
print(containSameElements(firstArray: array3, secondArray: array4)) //false
print(array1) //["a", "a", "b"]
print(array2) //["a", "b", "a"]
print(array3) //["a", "b", "c"]
print(array4) //["b", "c", "a", "d"]
like image 24
Khuong Avatar answered Sep 29 '22 02:09

Khuong


Here is a solution that does not require the element to be Comparable, but only Equatable. It is much less efficient than the sorting answers, so if your type can be made Comparable, use one of those.

extension Array where Element: Equatable {
    func equalContents(to other: [Element]) -> Bool {
        guard self.count == other.count else {return false}
        for e in self{
          guard self.filter{$0==e}.count == other.filter{$0==e}.count else {
            return false
          }
        }
        return true
    }
}
like image 33
Asa Zeren Avatar answered Sep 29 '22 02:09

Asa Zeren


If elements of your arrays are conforming to Hashable you can try to use the bag (it's like a set with the registration of each item amount). Here I will use a simplified version of this data structure based on Dictionary. This extension helps to create bag from array of Hashable:

extension Array where Element: Hashable {
    var asBag: [Element: Int] {
        return reduce(into: [:]) {
            $0.updateValue(($0[$1] ?? 0) + 1, forKey: $1)
        }
    }
}

Now you need to generate 2 bags from initial arrays and compare them. I wrapped it in this extension:

extension Array where Element: Hashable {
    func containSameElements(_ array: [Element]) -> Bool {
        let selfAsBag = asBag
        let arrayAsBag = array.asBag
        return selfAsBag.count == arrayAsBag.count && selfAsBag.allSatisfy {
            arrayAsBag[$0.key] == $0.value
        }
    }
}

This solution was tested with Swift 4.2/Xcode 10. If your current Xcode version is prior to 10.0 you can find the function allSatisfy of ArraySlice in Xcode9to10Preparation. You can install this library with CocoaPods.

like image 26
Roman Podymov Avatar answered Oct 01 '22 02:10

Roman Podymov