删除数组中的重复对象

我有一个包含我的Post对象的数组。 每个Post都有一个id属性。

有没有一种更有效的方法来find我的数组中重复的邮政编码比

 for post1 in posts { for post2 in posts { if post1.id == post2.id { posts.removeObject(post2) } } } 

我将build议2个解决scheme。

这两种方法都需要Post是可Hashable和可平等的

使post符合可哈希和可衡量

这里我假设你的Post结构(或者类)有一个Stringtypes的id属性。

 struct Post: Hashable, Equatable { let id: String var hashValue: Int { get { return id.hashValue } } } func ==(left:Post, right:Post) -> Bool { return left.id == right.id } 

解决scheme1(失去原来的订单)

要删除重复,你可以使用一个Set

 let uniquePosts = Array(Set(posts)) 

解决scheme2(保存订单)

 var alreadyThere = Set<Post>() let uniquePosts = posts.flatMap { (post) -> Post? in guard !alreadyThere.contains(post) else { return nil } alreadyThere.insert(post) return post } 

(更新了Swift 3)

正如我在这个问题的评论中所提到的那样,您可以在我们之前标记此post的线程中使用经过修改的Daniel Kroms解决scheme。 只要让你的Post对象可哈希(通过id属性隐含地equatable),并实现一个修改(使用Set而不是Dictionary ;在链接的方法中的字典值不被使用)Daniel Kroms uniq函数的版本如下:

 func uniq<S: Sequence, E: Hashable>(_ source: S) -> [E] where E == S.Iterator.Element { var seen = Set<E>() return source.filter { seen.update(with: $0) == nil } } struct Post : Hashable { var id : Int var hashValue : Int { return self.id } } func == (lhs: Post, rhs: Post) -> Bool { return lhs.id == rhs.id } var posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] print(Posts) /* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */ var myUniquePosts = uniq(posts) print(myUniquePosts) /* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)] */ 

这将在保持原始数组顺序的同时删除重复项。


辅助函数uniq作为Sequence扩展

或者使用一个自由函数,我们可以实现uniq作为受约束的Sequence扩展:

 extension Sequence where Iterator.Element: Hashable { func uniq() -> [Iterator.Element] { var seen = Set<Iterator.Element>() return filter { seen.update(with: $0) == nil } } } struct Post : Hashable { var id : Int var hashValue : Int { return self.id } } func == (lhs: Post, rhs: Post) -> Bool { return lhs.id == rhs.id } var posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] print(posts) /* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */ var myUniquePosts = posts.uniq() print(myUniquePosts) /* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)] */ 

我的“纯”的Swift解决scheme没有后置符合Hashable(由Set设置)

 struct Post { var id: Int } let posts = [Post(id: 1),Post(id: 2),Post(id: 1),Post(id: 3),Post(id: 4),Post(id: 2)] // (1) var res:[Post] = [] posts.forEach { (p) -> () in if !res.contains ({ $0.id == p.id }) { res.append(p) } } print(res) // [Post(id: 1), Post(id: 2), Post(id: 3), Post(id: 4)] // (2) let res2 = posts.reduce([]) { (var r, p) -> [Post] in if !r.contains ({ $0.id == p.id }) { r.append(p) } return r } print(res2) // [Post(id: 1), Post(id: 2), Post(id: 3), Post(id: 4)] 

我更喜欢(1)封装成函数(又名func unique(posts:[Post])->[Post] ),也许是一个扩展Array ….

使用Set

要使用它,使您的后可哈希和实现==运算符

 import Foundation class Post: Hashable, Equatable { let id:UInt let title:String let date:NSDate var hashValue: Int { get{ return Int(self.id) } } init(id:UInt, title:String, date:NSDate){ self.id = id self.title = title self.date = date } } func ==(lhs: Post, rhs: Post) -> Bool { return lhs.id == rhs.id } let posts = [Post(id: 11, title: "sadf", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 1; c.year = 2016; return c}())!), Post(id: 33, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!), Post(id: 22, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!), Post(id: 22, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!)] 

用重复数组创build一个数组

 let postsSet = Set(posts) 

这是无序的,创build一个新的数组,应用顺序。

 let uniquePosts = Array(postsSet).sort { (p1, p2) -> Bool in return p1.date.timeIntervalSince1970 < p2.date.timeIntervalSince1970 } 

您可以使用包装类,而不是使您的Post模型可哈希。 这个包装类将使用post对象属性来计算散列和相等性。
这个包装可以通过closuresconfiguration:

 class HashableWrapper<T>: Hashable { let object: T let equal: (obj1: T,obj2: T) -> Bool let hash: (obj: T) -> Int var hashValue:Int { get { return self.hash(obj: self.object) } } init(obj: T, equal:(obj1: T, obj2: T) -> Bool, hash: (obj: T) -> Int) { self.object = obj self.equal = equal self.hash = hash } } func ==<T>(lhs:HashableWrapper<T>, rhs:HashableWrapper<T>) -> Bool { return lhs.equal(obj1: lhs.object,obj2: rhs.object) } 

邮政可以很简单

 class Post { let id:UInt let title:String let date:NSDate init(id:UInt, title:String, date:NSDate){ self.id = id self.title = title self.date = date } } 

让我们像以前一样创build一些post

 let posts = [ Post(id: 3, title: "sadf", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 1; c.year = 2016; return c}())!), Post(id: 1, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!), Post(id: 2, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!), Post(id: 2, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 1; c.month = 12; c.year = 2015; return c}())!), Post(id: 1, title: "sdfr", date: NSCalendar.currentCalendar().dateFromComponents({let c = NSDateComponents(); c.day = 3; c.month = 1; c.year = 2016; return c}())!) ] 

现在我们用闭包为每个post创build包装对象,以确定相等和散列。 我们创build了这个集合。

 let wrappers = posts.map { (p) -> HashableWrapper<Post> in return HashableWrapper<Post>(obj: p, equal: { (obj1, obj2) -> Bool in return obj1.id == obj2.id }, hash: { (obj) -> Int in return Int(obj.id) }) } let s = Set(wrappers) 

现在我们提取包装的对象并按datesorting。

 let objects = s.map { (w) -> Post in return w.object }.sort { (p1, p2) -> Bool in return p1.date.timeIntervalSince1970 > p2.date.timeIntervalSince1970 } 

 print(objects.map{$0.id}) 

版画

 [1, 3, 2] 

而不是使用可哈希对象,你可以使用一个集合。 取一个你想删除重复的属性值,并用它作为你的testing值。 在我的例子中,我正在检查重复的ISBN值。

 do { try fetchRequestController.performFetch() print(fetchRequestController.fetchedObjects?.count) var set = Set<String>() for entry in fetchRequestController.fetchedObjects! { if set.contains(entry.isbn!){ fetchRequestController.managedObjectContext.delete(entry) }else { set.insert(entry.isbn!) } } try fetchRequestController.performFetch() print(fetchRequestController.fetchedObjects?.count) } catch { fatalError() } 

保持秩序,不增加额外的状态:

 func removeDuplicates<T: Equatable>(accumulator: [T], element: T) -> [T] { return accumulator.contains(element) ? accumulator : accumulator + [element] } posts.reduce([], removeDuplicates) 

在swift 3中请参考下面的代码:

 let filterSet = NSSet(array: orignalArray as NSArray as! [NSObject]) let filterArray = filterSet.allObjects as NSArray //NSArray print("Filter Array:\(filterArray)") 

Swift 3.1最优雅的解决scheme (Thanx dfri )

Apple Swift 3.1(swiftlang-802.0.51 clang-802.0.41)

 func uniq<S: Sequence, E: Hashable>(source: S) -> [E] where E==S.Iterator.Element { var seen: [E:Bool] = [:] return source.filter({ (v) -> Bool in return seen.updateValue(true, forKey: v) == nil }) } struct Post : Hashable { var id : Int var hashValue : Int { return self.id } } func == (lhs: Post, rhs: Post) -> Bool { return lhs.id == rhs.id } var Posts : [Post] = [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] print(Posts) /* [Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 1), Post(id: 3), Post(id: 5), Post(id: 7), Post(id: 9)] */ var myUniquePosts = uniq(source: Posts) print(myUniquePosts) /*[Post(id: 1), Post(id: 7), Post(id: 2), Post(id: 3), Post(id: 5), Post(id: 9)]*/ 
 struct Post { var id: Int } extension Post: Hashable { var hashValue: Int { return id } static func == (lhs: Post, rhs: Post) -> Bool { return lhs.id == rhs.id } } 

和额外的扩展

 public extension Sequence { func distinct<E: Hashable>() -> [E] where E == Iterator.Element { return Array(Set(self)) } }