3

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.

C.Johns
  • 10,185
  • 20
  • 102
  • 156
  • 1
    possible duplicate of [The best way to remove duplicate values from NSMutableArray in Objective-C?](http://stackoverflow.com/questions/1025674/the-best-way-to-remove-duplicate-values-from-nsmutablearray-in-objective-c), http://stackoverflow.com/questions/3966592/removing-duplicates-in-nsarray, http://stackoverflow.com/questions/3882515/remove-duplicates-nsmutablearray, http://stackoverflow.com/questions/5978574/removing-duplicates-from-nsmutablearray, among [others](https://www.google.com/search?q=site:stackoverflow.com+remove+duplicates+nsarray). – jscs Apr 26 '13 at 00:21
  • @JoshCaswell the bit I am having trouble with is the fact each NSDictionary object has two elements.. I need to base my method off that fact.. most if not all of your examples just show arrays with single elements.. in other words one date value instead of checking two date values per object – C.Johns Apr 26 '13 at 01:51

2 Answers2

7

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; }
omz
  • 53,243
  • 5
  • 129
  • 141
  • yes thats exactly what I am trying to achieve.. I will give your answer a try now and let you know how i go. – C.Johns Apr 26 '13 at 03:36
  • holy moly.. it worked. Man I have been coming back to this problem several times hoping that at one point either I would understand and solve it or someone would understand what i was asking and help me.. thank you so much.... I am super duper appreciative of your help.. oh man.. feels so good to have that problem out of my way... thanks a ton! – C.Johns Apr 26 '13 at 03:42
1

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.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • I have just finished some reading in which i see that you can compare objects as a whole to one another... Something I did not htink was possible, in my original question I neglected to mention another element in the NSDictionary thinking it was of no consequence to removing duplicates based off startYear finishYear.. It looks like you have offered a similar solution to which just literally a minute or two before your answer was submitted I had updated my question to define the face i have a unique element value in my NSDictionary.. – C.Johns Apr 26 '13 at 02:01
  • whoops.. have just been playing around with thew code.. i didnt see your update.. going to read now :) – C.Johns Apr 26 '13 at 02:39
  • Damn!!! your quote "I need some help removing objects whos StartYear and FinishYear match" is completely correct but my wording is completely wrong.... damn it was in fact supposed to read I would like to remove object whos startYear and finishyear match with other objects in the array. so in other words each object of the array is compared with each other so in the end you have an array of objects with unique startyear finishyear objects in the array.. i dearly hope this makes sense. – C.Johns Apr 26 '13 at 03:05
  • @C.Johns That's exactly what I described how to do. – Caleb Apr 26 '13 at 03:16
  • Oh its just I have tried your example and I get a unique array of object the thing is its not startyear finishyear unique because there is a ID element in the array.. so I found that I was still getting repeating years... I will go through your answer again and see if I missed something.. thanks for your patience – C.Johns Apr 26 '13 at 03:23
  • I would just like to thank you for your help.. unfortunately i didnt make alot of sense to begin with but you stuck in there and helped me as best you could.. and for that i would like to thank you.. – C.Johns Apr 26 '13 at 03:45