Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove objects with duplicate properties from Swift array

Tags:

ios

swift

The question here involves removing duplicate objects from an array:

Removing duplicate elements from an array in Swift

I instead need to remove objects that are not themselves duplicates, but have specific duplicate properties such as id.


I have an array containing my Post objects. Every Post has an id property.

Is there a more effective way to find duplicate Post ID's in my array than

for post1 in posts {
    for post2 in posts {
        if post1.id == post2.id {
            posts.removeObject(post2)
        }
    }
}
like image 840
Oscar Apeland Avatar asked Jan 10 '16 18:01

Oscar Apeland


People also ask

How to remove duplicate value from array Swift?

By converting the array to a Set , all duplicate values are automatically dropped from the array. We can then convert the set back to an array to get an array with all duplicate values removed. Because sets don't enforce any ordering, you might lose the original order of your array.

How do you remove duplicates from an array?

We can remove duplicate element in an array by 2 ways: using temporary array or using separate index. To remove the duplicate element from array, the array must be in sorted order. If array is not sorted, you can sort it by calling Arrays. sort(arr) method.

Can set have duplicate values Swift?

A set is a collection of unordered unique values. Therefore, it cannot contain a duplicate element.


4 Answers

I am going to suggest 2 solutions.

Both approaches will need Post to be Hashable and Equatable

Conforming Post to Hashable and Equatable

Here I am assuming your Post struct (or class) has an id property of 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)

To remove duplicated you can use a Set

let uniquePosts = Array(Set(posts)) 

Solution 2 (preserving the order)

var alreadyThere = Set<Post>() let uniquePosts = posts.flatMap { (post) -> Post? in     guard !alreadyThere.contains(post) else { return nil }     alreadyThere.insert(post)     return post } 
like image 194
Luca Angeletti Avatar answered Oct 14 '22 06:10

Luca Angeletti


You can create an empty array "uniquePosts", and loop through your array "Posts" to append elements to "uniquePosts" and every time you append you have to check if you already append the element or you didn't. The method "contains" can help you.

func removeDuplicateElements(post: [Post]) -> [Post] {     var uniquePosts = [Post]()     for post in posts {         if !uniquePosts.contains(where: {$0.postId == post.postId }) {             uniquePosts.append(post)         }     }     return uniquePosts } 
like image 30
marouan azizi Avatar answered Oct 14 '22 05:10

marouan azizi


A generic solution which preserves the original order is:

extension Array {
    func unique(selector:(Element,Element)->Bool) -> Array<Element> {
        return reduce(Array<Element>()){
            if let last = $0.last {
                return selector(last,$1) ? $0 : $0 + [$1]
            } else {
                return [$1]
            }
        }
    }
}

let uniquePosts = posts.unique{$0.id == $1.id }
like image 20
Mike Neilens Avatar answered Oct 14 '22 07:10

Mike Neilens


my 'pure' Swift solutions without Post conformance to Hashable (required by 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)]

I prefer (1) encapsulated into function (aka func unique(posts:[Post])->[Post] ), maybe an extension Array ....

like image 39
user3441734 Avatar answered Oct 14 '22 06:10

user3441734