How to find Duplicate Elements in Array? I have array of phone numbers so in the phone numbers i should start searching from the right side to the left side and find similar
var numbers = [1,2,3,4,5,6,6,6,7,8,8]
let dups = Dictionary(grouping: numbers, by: {$0}).filter { $1.count > 1 }.keys
// Results: [6, 8]
extension Array where Element: Hashable {
func similar() -> Self {
var used = [Element: Bool]()
return self.filter { used.updateValue(true, forKey: $0) != nil }
}
}
To find duplicates, you could build cross reference by phone number, then filter that down to duplicates only. For example, consider:
let contacts = [
Contact(name: "Rob", phone: "555-1111"),
Contact(name: "Richard", phone: "555-2222"),
Contact(name: "Rachel", phone: "555-1111"),
Contact(name: "Loren", phone: "555-2222"),
Contact(name: "Mary", phone: "555-3333"),
Contact(name: "Susie", phone: "555-2222")
]
In Swift 4, you can build the cross reference dictionary with:
let crossReference = Dictionary(grouping: contacts, by: { $0.phone })
Or
let crossReference = contacts.reduce(into: [String: [Contact]]()) {
$0[$1.phone, default: []].append($1)
}
Then, to find the duplicates:
let duplicates = crossReference
.filter { $1.count > 1 } // filter down to only those with multiple contacts
.sorted { $0.1.count > $1.1.count } // if you want, sort in descending order by number of duplicates
Clearly use whatever model types make sense for you, but the above uses the following Contact
type:
struct Contact {
let name: String
let phone: String
}
There are many, many ways to implement this, so I wouldn't focus on the implementation details of the above, but rather focus on the concept: Build cross reference original array by some key (e.g. phone number) and then filter results down to just those keys with duplicate values.
It sounds like you want to flatten this structure that reflects the duplicates, into a single array of contacts (I'm not sure why you'd want to do that, as you lose the structure identifying which are duplicates of each other), but if you want to do that, you can flatMap
it:
let flattenedDuplicates = crossReference
.filter { $1.count > 1 } // filter down to only those with multiple contacts
.flatMap { $0.1 } // flatten it down to just array of contacts that are duplicates of something else
For Swift 2 or 3 renditions, see previous renditions of this answer.
To filter an array based on properties, you can use this method:
extension Array {
func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{
var results = [Element]()
forEach { (element) in
let existingElements = results.filter {
return includeElement(lhs: element, rhs: $0)
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
Which you can call as followed, based on the contacts example of Rob:
let filteredContacts = myContacts.filterDuplicates { $0.name == $1.name && $0.phone == $1.phone }
Antoine's solution in Swift 3+ syntax
extension Array {
func filterDuplicates(includeElement: @escaping (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] {
var results = [Element]()
forEach { (element) in
let existingElements = results.filter {
return includeElement(element, $0)
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
I've found a way by using reduce, here is the code(Swift 4):
let testNumbers = [1,1,2,3,4,5,2]
let nondupicate = testNumbers.reduce(into: [Int]()) {
if !$0.contains($1) {
$0.append($1)
} else {
print("Found dupicate: \($1)")
}
}
As a side effect, it returns an array has no dupicated elements.
You can easily modify it for counting duplicated elements numbers, checking string arrays etc.