Подтвердить что ты не робот

Как проверить 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() продолжает удалять некоторые (обычно дублированные) объекты, содержащиеся в массиве.

Любая помощь будет оценена.

4b9b3361

Ответ 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