Reputation: 9743
I have a Swift array of coreData objects. The objects have three properties. I would like to filter the array to remove objects that share the same value for 2 of these properties.
Object properties are object.name, object.age, object.id
All properties are of type String.
I want to filter the array to return an array removing duplicate cases where object.name AND object.age are the same.
Upvotes: 3
Views: 2669
Reputation: 6911
Although Alain's solution is very nice, here's somewhat more swifty way which benefits from KeyPaths:
extension Array {
func filterDuplicates(by keyPath: PartialKeyPath<Element>) -> Self {
var uniqueKeys = Set<String>()
return self.filter { uniqueKeys.insert("\($0[keyPath: keyPath])").inserted }
}
}
Now you can use it like this:
yourArr.filterDuplicates(by: \YourClass.propertyName)
And if you want to use multiple properties to determine uniqueness, here's the solution for that:
extension Array {
func withRemovedDuplicates(by keyPaths: PartialKeyPath<Element>...) -> Self {
var uniqueKeys = Set<String>()
return self.filter { element in
uniqueKeys.insert(keyPaths.map { "\(element[keyPath: $0])" }.joined()).inserted
}
}
}
Use is this way:
yourArr.filterDuplicates(by: \YourClass.propertyOneName, \YourClass.propertyTwoName)
Upvotes: 1
Reputation: 42143
You could do it with a set:
var uniqueValues = Set<String>()
objectsArray = objectsArray.filter{ uniqueValues.insert("\($0.name)|\($0.age)").inserted}
You could also generalize the approach to cover other combinations by extending the Array type:
extension Array
{
func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element]
{
var uniqueKeys = Set<String>()
return filter{uniqueKeys.insert("\(keyValue($0))").inserted}
}
}
objectsArray = objectsArray.filterDuplicate{ ($0.name,$0.age) }
Upvotes: 8
Reputation: 9743
this is the solution that seems to work for me. maybe not the most elegant but simple enough.
objects is the array of coreData objects. The second array objectsArray is an empty array which is populated in the nested iteration with non age/name duplicate items.
var objects = [Object]()
//initialize the above array objects and fill with core data objects
objects = populateObjectsArrayWithCoreDataObjects()
//create a new empty array called objectsArray
var objectsArray = [Object]()
for index in 0..<self.objects.count {
let object = objects[index]
var isDuplicate = false
for index2 in (index + 1)..<self.objects.count {
let object2 = objects[index2]
if object.name == object2.name && object.age == object2.age {
isDuplicate = true
}
}
if isDuplicate == false {
objectsArray.append(item)
}
}
objects = objectsArray
Upvotes: 0