Как проверить Swift, если два массива содержат одни и те же элементы независимо от порядка, в котором эти элементы появляются?
Скажем, есть два массива...
var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a"]
Я хотел бы, чтобы результат сравнения этих двух массивов был истинным, и следующее...
var array1 = ["a", "b", "c"]
var array2 = ["b", "c", "a", "d"]
... false. Как я могу достичь этого в Swift? Я попытался преобразовать оба массива в набор, но по какой-то причине Set() продолжает удалять некоторые (обычно дублированные) объекты, содержащиеся в массиве.
Любая помощь будет оценена.
Ответы
Ответ 1
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
Ответ 2
вы можете сделать что-то вроде этого:
array1.sortInPlace()
array2.sortInPlace()
print(array1,array2)
if array1 == array2 {
print("equal")
} else {
print("not equal")
}
и если вы не хотите изменить исходный массив, мы можем сделать
let sorted1 = array1.sort()
let sorted2 = array2.sort()
if sorted1 == sorted2 {
print("equal")
}else {
print("not equal")
}
Ответ 3
Создайте функцию для сравнения:
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
}
}
Тогда:
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"]
Ответ 4
Вот решение, которое не требует, чтобы элемент был Comparable
, а только Equatable
. Это намного менее эффективно, чем сортировка ответов, поэтому, если ваш тип можно сделать сопоставимым, используйте один из них.
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
}
}
Ответ 5
Решение для Swift 4.1/Xcode 9.4:
extension Array where Element: Equatable {
func containSameElements(_ array: [Element]) -> Bool {
var selfCopy = self
var secondArrayCopy = array
while let currentItem = selfCopy.popLast() {
if let indexOfCurrentItem = secondArrayCopy.index(of: currentItem) {
secondArrayCopy.remove(at: indexOfCurrentItem)
} else {
return false
}
}
return secondArrayCopy.isEmpty
}
}
Основным преимуществом этого решения является то, что оно использует меньше памяти, чем другие (оно всегда создает только 2 временных массива). Также не требуется, чтобы Element
был Comparable
, просто чтобы он был Equatable
.
Ответ 6
Если элементы ваших массивов соответствуют Hashable
, вы можете попытаться использовать сумку (это как набор с регистрацией каждой суммы товара). Здесь я буду использовать упрощенную версию этой структуры данных на основе Dictionary
. Это расширение помогает создать сумку из массива Hashable
:
extension Array where Element: Hashable {
var asBag: [Element: Int] {
return reduce(into: [:]) {
$0.updateValue(($0[$1] ?? 0) + 1, forKey: $1)
}
}
}
Теперь вам нужно сгенерировать 2 пакета из начальных массивов и сравнить их. Я завернул его в это расширение:
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
}
}
}
Это решение было протестировано с Swift 4.2/Xcode 10. Если ваша текущая версия Xcode до 10.0, вы можете найти функцию allSatisfy
of ArraySlice
в Xcode9to10Preparation. Вы можете установить эту библиотеку с CocoaPods.
Ответ 7
Использование 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
}
Set
реализует Hashable
, поэтому задача состоит в том, чтобы реализовать хеш-функцию для работы с Set