remove duplicate valuse from NSMutable array [dupl

2019-05-10 22:13发布

问题:

This question already has an answer here:

  • The best way to remove duplicate values from NSMutableArray in Objective-C? 14 answers
  • How to compare and merge NSMutableArray 2 answers

I am trying to remove any duplicates from my sorted array... I thought I could do it using an example from another question of mine but it turns out to not even come close to working.

its a pretty horrible attempt, but its the only way i can figure out how to compare two elements of a single item(NSDictionary) in a NSMutableArray.

Here is my code example

I currently have a sorted array

 NSArray *duplicatesRemovedArray = [sortedArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
        NSDictionary *dictA = a;
        NSDictionary *dictB = b;

        NSString *startYear1 = dictA[kStartYear];
        NSString *finishYear1 = dictA[kFinishYear];
        NSString *allYear1 = [NSString stringWithFormat:@"%@%@",startYear1, finishYear1];
        NSString *startYear2 = dictB[kStartYear];
        NSString *finishYear2 = dictB[kFinishYear];
        NSString *allYear2 = [NSString stringWithFormat:@"%@%@",startYear2, finishYear2];

        return [allYear1 compare:allYear2];

    }];

if anyone has any ideas on how to create an NSArray of unique items that is what I am after, if you could give me any suggestions, code examples that would be greatly appreciated

Update: I should point out that my NSDictionary has another element within it an ID...

so I cannot just compare objects like in the examples you have listed... this was an oversight on my part. So effectivly the objects look like this

ID: 1234
STARTYEAR: 1999
FINISHYEAR: 2000

so I need some help removing objects whos StartYear and FinishYear match other objects start and finish year.

回答1:

So if I understood your question correctly, you want to filter your array in a way that if there's more than one item with the same year values (but possibly different IDs), only one of them is contained in the result.

A simple way to do that would be to iterate over the array, collecting start/finish years that you've already seen in a mutable set, and only including items in the result if they have a combination of start/finish year that you haven't yet added.

NSArray *array = @[@{@"ID": @(1234), @"STARTYEAR": @(1999), @"FINISHYEAR": @(2001)},
                   @{@"ID": @(1235), @"STARTYEAR": @(1999), @"FINISHYEAR": @(2001)},
                   @{@"ID": @(1236), @"STARTYEAR": @(1999), @"FINISHYEAR": @(2000)},
                   @{@"ID": @(1237), @"STARTYEAR": @(1999), @"FINISHYEAR": @(2000)}];

NSMutableArray *duplicatesRemoved = [NSMutableArray array];
NSMutableSet *seenYears = [NSMutableSet set];
for (NSDictionary *item in array) {
    //Extract the part of the dictionary that you want to be unique:
    NSDictionary *yearDict = [item dictionaryWithValuesForKeys:@[@"STARTYEAR", @"FINISHYEAR"]];
    if ([seenYears containsObject:yearDict]) {
        continue;
    }
    [seenYears addObject:yearDict];
    [duplicatesRemoved addObject:item];
}
NSLog(@"%@", duplicatesRemoved);

In this example, this would result in these two items:

{ FINISHYEAR = 2001; ID = 1234; STARTYEAR = 1999; }
{ FINISHYEAR = 2000; ID = 1236; STARTYEAR = 1999; }


回答2:

Provided you don't care about preserving the order of items in the array, a quick and easy way to ensure that the objects in an array are distinct is to convert the array to a set and then back to an array. The elements in a set are distinct and unordered.

Here's an example:

NSArray *a = @[@"a", @"b", @"a", @"c", [NSString stringWithFormat:@"%@", @"a"]];
NSLog(@"a is: %@", a);
NSSet *s = [NSSet setWithArray:a];
NSArray *b = [s allObjects];
NSLog(@"b is: %@", s);

The output from the above looks like:

a is: (
    a,
    b,
    a,
    c,
    a
)
b is: {(
    b,
    c,
    a
)}

So, b is an array containing all the distinct objects from a. A shorter version that does the same thing is:

NSArray *a = @[@"a", @"b", @"a", @"c", [NSString stringWithFormat:@"%@", @"a"]];
NSArray *b = [[NSSet setWithArray:a] allObjects];

If you do care about order, then you have two choices: use the method above and reorder the objects afterward, or use a different method. If you only want the objects to stay sorted, then you can of course just sort the resulting array of distinct objects to restore the sorted order. Alternatively, if the array is sorted, you can use the fact that sorting will cause duplicate objects to end up next to each other. So, just scan through the array comparing each element with the subsequent element, and remove the first one if they're the same.

If you need to preserve some order that can't be computed, then you're kinda stuck. You could copy the array, apply the method above to the copy, and then use the original array to help you restore the original order.

I need some help removing objects whos StartYear and FinishYear match

This is a little more complicated, but not much. Consider the method of removing duplicates by sorting that I mentioned above. If you sort your array of dictionaries using startYear and finishYear as keys, you should get an array where objects that have the same start and finish year will be adjacent. That is, all the objects with the same start year will be clustered together, and within each cluster all the objects that have the same finish year will be clustered together. You can do that kind of sorting easily using -sortedArrayUsingDescriptors:. Here's how you'd go about it:

NSSortDescriptor *start = [NSSortDescriptor sortDescriptorWithKey:@"startYear" ascending:YES];
NSSortDescriptor *finish = [NSSortDescriptor sortDescriptorWithKey:@"finishYear" ascending:YES];
NSArray *sortedArray = [unsortedArray sortedArrayUsingDescriptors:@[start, finish]];

After that, proceed as described above -- scan through the array comparing each item with the subsequent item. If they're the same, do nothing. If they're different, or if you reach the end of the array, copy the element into a new array (or add its index to an index set, or whatever). Just be aware that modifying the same array as you scan through it is an easy way to create bugs (and if you use enumerators or fast enumeration, you must not modify the array). That's why I suggested copying the unique items to a new array.