我有一个带有自定义对象的数组。
我想用重复的属性弹出重复的对象:
let product = Product()
product.subCategory = "one"
let product2 = Product()
product2.subCategory = "two"
let product3 = Product()
product3.subCategory = "two"
let array = [product,product2,product3]
在这种情况下,弹出product2 or product3
答案 0 :(得分:9)
您可以使用Swift Set
:
let array = [product,product2,product3]
let set = Set(array)
您必须使Product
符合Hashable
(因此,Equatable
):
class Product : Hashable {
var subCategory = ""
var hashValue: Int { return subCategory.hashValue }
}
func ==(lhs: Product, rhs: Product) -> Bool {
return lhs.subCategory == rhs.subCategory
}
而且,如果Product
是NSObject
子类,则必须覆盖isEqual
:
override func isEqual(object: AnyObject?) -> Bool {
if let product = object as? Product {
return product == self
} else {
return false
}
}
显然,修改这些内容以反映您的课程中可能包含的其他属性。例如:
class Product : Hashable {
var category = ""
var subCategory = ""
var hashValue: Int { return [category, subCategory].hashValue }
}
func ==(lhs: Product, rhs: Product) -> Bool {
return lhs.category == rhs.category && lhs.subCategory == rhs.subCategory
}
答案 1 :(得分:7)
这是一个Array扩展,用于根据给定的键返回唯一的对象列表:
extension Array {
func unique<T:Hashable>(map: ((Element) -> (T))) -> [Element] {
var set = Set<T>() //the unique list kept in a Set for fast retrieval
var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
for value in self {
if !set.contains(map(value)) {
set.insert(map(value))
arrayOrdered.append(value)
}
}
return arrayOrdered
}
}
使用这个你可以这样
let unique = [product,product2,product3].unique{$0.subCategory}
这样做的好处是不需要Hashable,并且能够根据任何字段或组合返回唯一列表
答案 2 :(得分:1)
如果Product
符合Equatable
,产品根据其子类别相等(并且您不关心订单),则可以将对象添加到集合中,并获取数组从那套:
let array = [product,product2,product3]
let set = NSSet(array: array)
let uniqueArray = set.allObjects
或
let array = [product,product2,product3]
let set = Set(array)
let uniqueArray = Array(set)
答案 3 :(得分:1)
class Product {
var subCategory: String = ""
}
let product = Product()
product.subCategory = "one"
let product2 = Product()
product2.subCategory = "two"
let product3 = Product()
product3.subCategory = "two"
let array = [product,product2,product3]
extension Product : Hashable {
var hashValue: Int {
return subCategory.hashValue
}
}
func ==(lhs: Product, rhs: Product)->Bool {
return lhs.subCategory == rhs.subCategory
}
let set = Set(array)
set.forEach { (p) -> () in
print(p, p.subCategory)
}
/*
Product one
Product two
*/
如果项目是否是集合的一部分并不依赖于hashValue,则取决于比较。如果您的产品符合Hashable,则应符合Equatable。如果你需要创建集合仅仅依赖于subCategory,那么比较应该完全取决于subCategory。如果您需要以其他方式比较您的产品,这可能是一个很大的麻烦
答案 4 :(得分:1)
如果您的类符合Hashable协议,并且您希望保留原始数组顺序,则可以按如下方式创建扩展名:
extension Array where Element: Hashable {
var uniqueElements: [Element] {
var elements: [Element] = []
for element in self {
if let _ = elements.indexOf(element) {
print("item found")
} else {
print("item not found, add it")
elements.append(element)
}
}
return elements
}
}
答案 5 :(得分:0)
这是 KeyPath 的基于 Ciprian Rarau' solution 的版本
extension Array {
func unique<T: Hashable>(by keyPath: KeyPath<Element, T>) -> [Element] {
var set = Set<T>()
return self.reduce(into: [Element]()) { result, value in
guard !set.contains(value[keyPath: keyPath]) else {
return
}
set.insert(value[keyPath: keyPath])
result.append(value)
}
}
}
示例用法:
let unique = [product, product2, product3].unique(by: \.subCategory)