问题
Suppose I have a class Event, and it has 2 properties: action (NSString) and date (NSDate).
And suppose I have an array of Event objects. The problem is that "date" properties can match.
I need to remove the duplicates, meaning that 2 different objects with the same date IS a duplicate.
I can remove duplicates in any array of strings or nsdates, they are easy to compare. But how to do it with complex objects, where their properties are to be compared?
Don't ask me what I did so far, cos' the only thing coming in my mind is a bubble sort, but it's a newbie solution, and slow.
Quite any help is highly appreciated (links, tuts, code).
Thanks in advance.
EDIT
Thanks to dasblinkenlight, I have made a custom method:
- (NSArray *)removeDuplicatesInArray:(NSArray*)arrayToFilter{
NSMutableSet *seenDates = [NSMutableSet set];
NSPredicate *dupDatesPred = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind) {
YourClass *e = (YourClass*)obj;
BOOL seen = [seenDates containsObject:e.propertyName];
if (!seen) {
[seenDates addObject:e.when];
}
return !seen;
}];
return [arrayToFilter filteredArrayUsingPredicate:dupDatesPred];
}
Here YourClass
is the name of your class the object belongs to, and propertyName
is the property of that object you are going to compare.
Suppose self.arrayWithObjects contains the objects of YourClass.
After populating it, use
self.arrayWithObjects = [self removeDuplicatesInArray:self.arrayWithObjects];
and you are done.
All credits to dasblinkenlight. Cheers!
回答1:
You can create an NSMutableSet
of dates, iterate your event list, and add only events the date for which you have not encountered before.
NSMutableSet *seenDates = [NSMutableSet set];
NSPredicate *dupDatesPred = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind) {
Event *e = (Event*)obj;
BOOL seen = [seenDates containsObject:e.date];
if (!seen) {
[seenDates addObject:e.date];
}
return !seen;
}];
NSArray *events = ... // This is your array which needs to be filtered
NSArray *filtered = [events filteredArrayUsingPredicate:dupDatesPred];
回答2:
Wouldn't this work with kvc. I suppose the following solution could work in your case;
Event *event1 = [[Event alloc] init];
event1.name = @"Event1";
event1.date = [NSDate distantFuture];
Event *event2 = [[Event alloc] init];
event2.name = @"Event2";
event2.date = [NSDate distantPast];
Event *event3 = [[Event alloc] init];
event3.name = @"Event1";
event3.date = [NSDate distantPast];
NSArray *array = @[event1, event2, event3];
NSArray *filteredEvents = [array valueForKeyPath:@"@distinctUnionOfObjects.name"];
回答3:
NSMutableArray *leftObjects = [duplicateArray mutableCopy];
NSMutableArray *nonDuplicates = [NSMutableArray new];
while (leftObjects.count > 0)
{
YourClass *object = [leftObjects objectAtIndex:0];
// find all objects matching your comaprison equality definition for YourClass
NSArray *matches = [leftObjects filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(YourClass *evaluatedObject, NSDictionary *bindings)
{
return (evaluatedObject.name == object.name);
}] ];
[leftObjects removeObjectsInArray:matches];
// add first object (arbitrary, may decide which duplicate to pick)
[nonDuplicates addObject:matches.firstObject];
}
回答4:
I think the most effective way is to use NSDictionary
to store the object as value and the property value as key, and before adding any object to the dictionary you check if it exist or not which is O(1) operation, i.e. the whole process will take O(n)
Here is the code
- (NSArray *)removeDuplicatesFromArray:(NSArray *)array onProperty:(NSString *)propertyName {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (int i=0; i<array.count; i++) {
NSManagedObject *currentItem = array[i];
NSString *propertyValue = [currentItem valueForKey:propertyName];
if ([dictionary valueForKey:propertyValue] == nil) {
[dictionary setValue:currentItem forKey:propertyValue];
}
}
NSArray *uniqueItems = [dictionary allValues];
return uniqueItems;
}
you can use it as the following
self.arrayWithObjects = [self removeDuplicatesFromArray:self.arrayWithObjects onProperty:@"when"];
回答5:
Here is a Swift extension on the NSArray class that removes duplicates for the specified property:
extension NSArray {
/**
- parameter property: the name of the property to check for duplicates
- returns: an array of objects without objects that share an identical value of the specified property
*/
func arrayWithoutObjectsOfDuplicateProperty(property : String) -> [AnyObject] {
var seenInstances = NSMutableSet()
let predicate = NSPredicate { (obj, bind) -> Bool in
let seen = seenInstances.containsObject(obj.valueForKey(property)!)
if !seen {
seenInstances.addObject(obj.valueForKey(property)!)
}
return !seen
}
return self.filteredArrayUsingPredicate(predicate)
}
}
回答6:
Here is working Swift code snipped which does remove duplicates while keeping the order of elements.
// Custom Struct. Can be also class.
// Need to be `equitable` in order to use `contains` method below
struct CustomStruct : Equatable {
let name: String
let lastName : String
}
// conform to Equatable protocol. feel free to change the logic of "equality"
func ==(lhs: CustomStruct, rhs: CustomStruct) -> Bool {
return (lhs.name == rhs.name && lhs.lastName == rhs.lastName)
}
let categories = [CustomStruct(name: "name1", lastName: "lastName1"),
CustomStruct(name: "name2", lastName: "lastName1"),
CustomStruct(name: "name1", lastName: "lastName1")]
print(categories.count) // prints 3
// remove duplicates (and keep initial order of elements)
let uniq1 : [CustomStruct] = categories.reduce([]) { $0.contains($1) ? $0 : $0 + [$1] }
print(uniq1.count) // prints 2 - third element has removed
And just if you are wondering how this reduce magic works - here is exactly the same, but using more expanded reduce syntax
let uniq2 : [CustomStruct] = categories.reduce([]) { (result, category) in
var newResult = result
if (newResult.contains(category)) {}
else {
newResult.append(category)
}
return newResult
}
uniq2.count // prints 2 - third element has removed
You can simply copy-paste this code into a Swift Playground and play around.
来源:https://stackoverflow.com/questions/13499231/remove-duplicates-from-array-comparing-the-properties-of-its-objects