数组Swift中的唯一对象

时间:2015-11-22 22:29:47

标签: ios arrays swift

我有一个带有自定义对象的数组。

我想用重复的属性弹出重复的对象:

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

6 个答案:

答案 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
}

而且,如果ProductNSObject子类,则必须覆盖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)