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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:33:45  来源:igfitidea点击:

Remove duplicate objects in an array

iosswift

提问by Oscar Apeland

I have an array containing my Postobjects. Every Posthas an idproperty.

我有一个包含我的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 Postto be Hashableand Equatable

这两种方法都需要PostHashable和 Equatable

Conforming Post to Hashable and Equatable

使 Post 符合 Hashable 和 Equatable

Here I am assuming your Poststruct (or class) has an idproperty of type String.

在这里,我假设您的Post结构(或类)具有idtype的属性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 Postobject hashable (implicitly equatable via idproperty) and implement a modified (using Setrather than Dictionary; the dict value in the linked method is not used anyway) version of Daniel Kroms uniqfunction 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 uniqas a Sequenceextension

辅助函数uniq作为Sequence扩展

Alternatively to using a free function, we could implement uniqas a constrained Sequenceextension:

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 Postmodel 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

印刷

##代码##