ios 删除数组中的重复对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34709066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Remove duplicate objects in an array
提问by Oscar Apeland
I have an array containing my Post
objects. Every Post
has an id
property.
我有一个包含我的Post
对象的数组。每个人Post
都有一个id
财产。
Is there a more effective way to find duplicate Post ID's in my array than
有没有比在我的数组中找到重复的帖子 ID 更有效的方法
for post1 in posts {
for post2 in posts {
if post1.id == post2.id {
posts.removeObject(post2)
}
}
}
回答by Luca Angeletti
I am going to suggest 2 solutions.
我将建议2个解决方案。
Both approaches will need Post
to be Hashable
and Equatable
这两种方法都需要Post
是Hashable
和 Equatable
Conforming Post to Hashable and Equatable
使 Post 符合 Hashable 和 Equatable
Here I am assuming your Post
struct (or class) has an id
property of type String
.
在这里,我假设您的Post
结构(或类)具有id
type的属性String
。
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
}
Solution 1 (losing the original order)
解决方案1(丢失原订单)
To remove duplicated you can use a Set
要删除重复的,您可以使用 Set
let uniquePosts = Array(Set(posts))
Solution 2 (preserving the order)
解决方案2(保留顺序)
var alreadyThere = Set<Post>()
let uniquePosts = posts.flatMap { (post) -> Post? in
guard !alreadyThere.contains(post) else { return nil }
alreadyThere.insert(post)
return post
}
回答by marouan azizi
func removeDuplicateElements(post: [Post]) -> [Post] {
var uniquePosts = [Post]()
for post in posts {
if !uniquePosts.contains(where: {for (index, element) in arr.enumerated().reversed() {
if arr.filter({ let filterSet = NSSet(array: orignalArray as NSArray as! [NSObject])
let filterArray = filterSet.allObjects as NSArray //NSArray
print("Filter Array:\(filterArray)")
== element}).count > 1 {
arr.remove(at: index)
}
}
.postId == post.postId }) {
uniquePosts.append(post)
}
}
return uniquePosts
}
回答by vitas168
This works for multidimensional arrays as well:
这也适用于多维数组:
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 ({ func uniq<S: Sequence, E: Hashable>(_ source: S) -> [E] where E == S.Iterator.Element {
var seen = Set<E>()
return source.filter { seen.update(with: extension Sequence where Iterator.Element: Hashable {
func uniq() -> [Iterator.Element] {
var seen = Set<Iterator.Element>()
return filter { seen.update(with: func removeDuplicates<T: Equatable>(accumulator: [T], element: T) -> [T] {
return accumulator.contains(element) ?
accumulator :
accumulator + [element]
}
posts.reduce([], removeDuplicates)
) == 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)] */
) == 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)] */
.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 ({ extension Array where Element: Hashable {
func removingDuplicates<T: Hashable>(byKey key: (Element) -> T) -> [Element] {
var result = [Element]()
var seen = Set<T>()
for value in self {
if seen.insert(key(value)).inserted {
result.append(value)
}
}
return result
}
}
.id == p.id }) {
r.append(p)
}
return r
}
print(res2) // [Post(id: 1), Post(id: 2), Post(id: 3), Post(id: 4)]
回答by Kiran K
In swift 3 refer below code:
在 swift 3 中,请参考以下代码:
struct Client:Hashable {
let uid :String
let notifications:Bool
init(uid:String,dictionary:[String:Any]) {
self.uid = uid
self.notifications = dictionary["notificationsStatus"] as? Bool ?? false
}
static func == (lhs: Client, rhs: Client) -> Bool {
return lhs.uid == rhs.uid
}
}
回答by user3441734
my 'pure' Swift solutions without Post conformance to Hashable (required by Set )
我的“纯”Swift 解决方案不符合 Hashable 的 Post 一致性(由 Set 要求)
arrayClients.removingDuplicates(byKey: { 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
}
}
.uid })
I prefer (1) encapsulated into function (aka func unique(posts:[Post])->[Post]
), maybe an extension Array ....
我更喜欢(1)封装成函数(又名func unique(posts:[Post])->[Post]
),也许是一个扩展数组....
回答by dfri
(Updated for Swift 3)
(为 Swift 3 更新)
As I mentioned in my comment to the question, you can make use of a modified Daniel Kroms solution in the thread we previously marked this post to be duplicate of. Just make your Post
object hashable (implicitly equatable via id
property) and implement a modified (using Set
rather than Dictionary
; the dict value in the linked method is not used anyway) version of Daniel Kroms uniq
function as follows:
正如我在对该问题的评论中提到的,您可以在我们之前将此帖子标记为重复的线程中使用修改后的 Daniel Kroms 解决方案。只需使您的Post
对象可散列(通过id
属性隐式等同)并实现Daniel Kroms函数的修改版本(使用Set
而不是Dictionary
; 无论如何都不使用链接方法中的 dict 值)uniq
,如下所示:
let uniquePosts = posts.unique{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}())!)]
.id ?? ""}
This will remove duplicates while maintaining the order of the original array.
这将删除重复项,同时保持原始数组的顺序。
Helper function uniq
as a Sequence
extension
辅助函数uniq
作为Sequence
扩展
Alternatively to using a free function, we could implement uniq
as a constrained Sequence
extension:
uniq
除了使用自由函数,我们还可以将其实现为受约束的Sequence
扩展:
let postsSet = Set(posts)
回答by mbdavis
Preserving order, without adding extra state:
保留顺序,不添加额外状态:
let uniquePosts = Array(postsSet).sort { (p1, p2) -> Bool in
return p1.date.timeIntervalSince1970 < p2.date.timeIntervalSince1970
}
回答by Danielvgftv
My solution on Swift 5:
我在 Swift 5 上的解决方案:
Add Extension:
添加扩展:
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 Client, important have the class like Hashable :
类客户端,重要的是像 Hashable 这样的类:
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
}
}
Use:
用:
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}())!)
]
Have a good day swift lovers ??
有一个美好的一天 swift 爱好者??
回答by Max Niagolov
There is a good example from this post
这篇文章中有一个很好的例子
Here is an Array extension to return the unique list of objects based on a given key:
这是一个基于给定键返回唯一对象列表的 Array 扩展:
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)
for your example do:
对于您的示例,请执行以下操作:
let objects = s.map { (w) -> Post in
return w.object
}.sort { (p1, p2) -> Bool in
return p1.date.timeIntervalSince1970 > p2.date.timeIntervalSince1970
}
回答by vikingosegundo
use a Set
使用集合
To use it, make your Post hashable and implement the ==
operator
要使用它,请使您的 Post 可散列并实现==
运算符
print(objects.map{[1, 3, 2]
.id})
Create set from array with duplicates
从具有重复项的数组创建集
##代码##This is unordered, create a new array, apply order.
这是无序的,创建一个新数组,应用顺序。
##代码##Instead of making your Post
model hashable, you could also use a wrapper class. This wrapper class would use the post objects property to calculate the hash and equality.
this wrapper could be configurable through closure:
除了使您的Post
模型可散列,您还可以使用包装类。这个包装类将使用 post objects 属性来计算散列和相等性。
这个包装器可以通过闭包进行配置:
The Post could be simply
邮政可能只是
##代码##Let's create some post as before
让我们像以前一样创建一些帖子
##代码##Now we create wrapper objects for every post with closure to determine equality and the hash. And we create the set.
现在我们为每个带有闭包的帖子创建包装器对象以确定相等性和散列。我们创建了集合。
##代码##Now we extract the wrapped objects and sort it by date.
现在我们提取包装的对象并按日期对其进行排序。
##代码##and
和
##代码##prints
印刷
##代码##