Проблема в том, что вы ожидаете, что два Option
будут равны, если они имеют одинаковые title
и key
, но по умолчанию Swift также проверяет value
. Поэтому два Option
с разными value
считаются разными.
Симметричная разница возвращает новый набор с элементами, которые находятся либо в этом наборе, либо в заданной последовательности, но не в обоих. Поскольку вы изменили значения, вы получите объединение двух наборов, потому что они не имеют ничего общего.
Это можно исправить, явно реализовав функции hash(into:)
и ==
, чтобы игнорировать value
при проверке на равенство:
struct Option: Hashable, CustomStringConvertible {
var title: String
var key: String
var value: Int
var description: String { return "{title: \"\(title)\", key: \"\(key)\", value: \(value)}" }
func hash(into hasher: inout Hasher) {
hasher.combine(title)
hasher.combine(key)
}
static func ==(lhs: Option, rhs: Option) -> Bool {
return lhs.title == rhs.title && lhs.key == rhs.key
}
}
var apple = Option(title: "Apple", key: "apple", value: 0)
var grape = Option(title: "Grape", key: "grape", value: 0)
var banana = Option(title: "Banana", key: "banana", value: 0)
var papaya = Option(title: "Papaya", key: "papaya", value: 0)
var options = [apple, grape, banana, papaya]
apple.value = 1
grape.value = 2
var ranked = [apple, grape]
let originalSet: Set<Option> = Set(options)
var rankedSet: Set<Option> = Set(ranked)
let remainingOptions = originalSet.symmetricDifference(rankedSet)
print(remainingOptions)
[{title: "Papaya", key: "papaya", value: 0}, {title: "Banana", key: "banana", value: 0}]
Примечание: symmetricDifference
принимает последовательность, поэтому нет необходимости преобразовывать ranked
в Set
, вы можете просто использовать массив:
let remainingOptions = originalSet.symmetricDifference(ranked)
Другой вариант: использовать фильтр
Вместо использования Set
s и symmetricDifference
вы можете использовать map
, чтобы получить массив keys
из массива ranked
, а затем использовать filter
в массиве options
, чтобы получить remaining
параметры, которые не соответствуют этим keys
:
let rankedKeys = ranked.map { $0.key }
let remaining = options.filter { !rankedKeys.contains($0.key) }
Для этого не требуется изменять структуру Option
по сравнению с исходным определением.