Reputation:
I did find duplicate contacts list from this method , now i'm stuck in merging the duplicates, any idea how i can do this.
I fetched duplicate using this code Referenced from previous question.
let formatter = CNContactFormatter()
formatter.style = .fullName
let keys = [CNContactIdentifierKey as CNKeyDescriptor, CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
let request = CNContactFetchRequest(keysToFetch: keys)
var contactsByName = [String: [CNContact]]()
try! self.store.enumerateContacts(with: request) { contact, stop in
guard let name = formatter.string(from: contact) else { return }
contactsByName[name] = (contactsByName[name] ?? []) + [contact] // or in Swift 4, `contactsByName[name, default: []].append(contact)`
}
let duplicates = contactsByName.filter { $1.count > 1 }
Upvotes: 3
Views: 2297
Reputation: 1
Two things I'm asking myself while reading your function.
newContact.phoneNumbers: It seems like you append ALL the numbers from the 2 contacts. If the 2 duplicated contacts have the same number, then the newContact will then have the same number twice in it's list, right?
It feels like the newContact you are creating is losing lots of information. Like nickname or prefix (Doctor, etc…).
Thanks for this compact code anyway :)
Upvotes: 0
Reputation: 1
I modified this a little bit. Maybe it helps..
extension Array where Element == String {
var bestElement: String? {
var options: [String : Int] = [:]
for element in self {
if let result = options[element] {
options[element] = result + 1
} else {
options[element] = 1
}
}
return options.sorted { $0.1 > $1.1 }.first?.key
}
}
static func merge(duplicates: [CNContact]) -> CNContact {
// EMPTY CNCONTACT PROPERTIES
var givenName: [String] = []
var familyName: [String] = []
var organizationName: [String] = []
var notes: [String] = []
var phoneNumbers: [CNLabeledValue<CNPhoneNumber>] = []
var emailAddresses: [CNLabeledValue<NSString>] = []
var postalAddresses: [CNLabeledValue<CNPostalAddress>] = []
var urlAddresses: [CNLabeledValue<NSString>] = []
// COLLECT VALUES
for contact in duplicates {
givenName.append(contact.givenName)
familyName.append(contact.familyName)
organizationName.append(contact.organizationName)
notes.append(contact.note)
contact.phoneNumbers.forEach { phoneNumbers.append($0) }
contact.emailAddresses.forEach { emailAddresses.append($0) }
contact.postalAddresses.forEach { postalAddresses.append($0) }
contact.urlAddresses.forEach { urlAddresses.append($0) }
}
// MERGE TO NEW CONTACT
let newContact = CNMutableContact()
newContact.givenName = givenName.bestElement ?? ""
newContact.familyName = familyName.bestElement ?? ""
newContact.organizationName = organizationName.bestElement ?? ""
newContact.note = notes.joined(separator: "\n")
newContact.phoneNumbers = phoneNumbers
newContact.emailAddresses = emailAddresses
newContact.postalAddresses = postalAddresses
newContact.urlAddresses = urlAddresses
return newContact
}
Upvotes: 0
Reputation: 3096
If you followed my previous answer for fetching duplicates list after you can use this code to merge duplicates.
func mergeAllDuplicates() -> CNContact {
let duplicates: [Array<CNContact>] = //Array of Duplicates Contacts
for item in duplicates {
// CNCONTACT PROPERTIES
var namePrefix: [String] = [String]()
var givenName: [String] = [String]()
var middleName: [String] = [String]()
var familyName: [String] = [String]()
var previousFamilyName: [String] = [String]()
var nameSuffix: [String] = [String]()
var nickname: [String] = [String]()
var organizationName: [String] = [String]()
var departmentName: [String] = [String]()
var jobTitle: [String] = [String]()
var phoneNumbers: [CNPhoneNumber] = [CNPhoneNumber]()
var emailAddresses: [NSString] = [NSString]()
var postalAddresses: [CNPostalAddress] = [CNPostalAddress]()
var urlAddresses: [NSString] = [NSString]()
var contactRelations: [CNContactRelation] = [CNContactRelation]()
var socialProfiles: [CNSocialProfile] = [CNSocialProfile]()
var instantMessageAddresses: [CNInstantMessageAddress] = [CNInstantMessageAddress]()
// Filter
for items in item {
namePrefix.append(items.namePrefix)
givenName.append(items.givenName)
middleName.append(items.middleName)
familyName.append(items.familyName)
previousFamilyName.append(items.previousFamilyName)
nameSuffix.append(items.nameSuffix)
nickname.append(items.nickname)
organizationName.append(items.organizationName)
departmentName.append(items.departmentName)
jobTitle.append(items.jobTitle)
for number in items.phoneNumbers {
phoneNumbers.append(number.value)
}
for email in items.emailAddresses {
emailAddresses.append(email.value)
}
for postal in items.postalAddresses {
postalAddresses.append(postal.value)
}
for url in items.urlAddresses {
urlAddresses.append(url.value)
}
for relation in items.contactRelations {
contactRelations.append(relation.value)
}
for social in items.socialProfiles {
socialProfiles.append(social.value)
}
for message in items.instantMessageAddresses {
instantMessageAddresses.append(message.value)
}
}
let newContact = CNMutableContact()
newContact.namePrefix = Array(Set(namePrefix))[0]
newContact.givenName = Array(Set(givenName))[0]
newContact.middleName = Array(Set(middleName))[0]
newContact.familyName = Array(Set(familyName))[0]
newContact.previousFamilyName = Array(Set(previousFamilyName))[0]
newContact.nameSuffix = Array(Set(nameSuffix))[0]
newContact.nickname = Array(Set(nickname))[0]
newContact.organizationName = Array(Set(namePrefix))[0]
newContact.departmentName = Array(Set(namePrefix))[0]
newContact.jobTitle = Array(Set(namePrefix))[0]
for item in Array(Set(phoneNumbers)) {
newContact.phoneNumbers.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(emailAddresses)) {
newContact.emailAddresses.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(postalAddresses)) {
newContact.postalAddresses.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(urlAddresses)) {
newContact.urlAddresses.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(contactRelations)) {
newContact.contactRelations.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(socialProfiles)) {
newContact.socialProfiles.append(CNLabeledValue(label: CNLabelHome, value: item))
}
for item in Array(Set(instantMessageAddresses)) {
newContact.instantMessageAddresses.append(CNLabeledValue(label: CNLabelHome, value: item))
}
return newContact
}
}
This approach will take quite a memory so I suggest, use this approach as a reference.
Upvotes: 0