How do I get unique values from an array
Asked Answered
C

4

6

Please note this is for OSX, not for iOS.

I have looked and tried some solutions in other SO questions, but none seem to work for me, hence this:

I want to get a unique set of years out of an array.

My code is this:

NSMutableArray * unique = [NSMutableArray array];
        NSMutableSet * processed = [NSMutableSet set];
        for (yearString in yearStringArray) {
            if (![processed containsObject:yearString] == NO) {
                [unique addObject:yearString];
            }
            [processed addObject:yearString];
        }

        NSLog(@"unique: %@",unique );
        NSLog(@"processed: %@",processed );

    }];

The console returns:

unique: (
        (
        1941,
        1942,
        1943,
        1945,
        1948,
        1948,
        1948,
        1949
    )

processed: {(
        (
        1941,
        1942,
        1943,
        1945,
        1948,
        1948,
        1948,
        1949
    )
)}

I only want one 1948. I would appreciate any help.

UPDATES: Thanks for the answers all. Keep em coming please!!!

These are the code snips I've tried now:

1.

for (yearString in yearStringArray) {
            if ([processed containsObject:yearString] == NO) {
                [unique addObject:yearString];
            }
            [processed addObject:yearString];
        }

2.

   NSString *yearString = [[NSString alloc] init];
    NSArray *objectArray = [[NSArray alloc] init];
    [objectArray = objects copy];

    for (int j = 0; j <= objectArray.count; j++) {
        NSString *yearString = [objectArray valueForKey:@"year"];
        [yearStringArray addObject:yearString];
    }


    NSMutableArray * unique = [NSMutableArray array];
    NSMutableSet * processed = [NSMutableSet set];


    for (yearString in yearStringArray) {

        [unique addObject:yearString];
        [processed addObject:yearString];
    }

    NSArray *processed2 = [[NSSet setWithArray:unique] allObjects];
    NSLog(@"unique: %@",unique );
    NSLog(@"processed: %@",processed );
    NSLog(@"processed2: %@",processed2 );
    //[self setYears];
}];

3.

NSString *yearString = [[NSString alloc] init];
    NSArray *objectArray = [[NSArray alloc] init];
    [objectArray = objects copy];

    for (int j = 0; j <= objectArray.count; j++) {
        yearString = [objectArray valueForKey:@"year"];
        [yearStringArray addObject:yearString];
    }



    NSArray *uniqueYears = [yearStringArray valueForKeyPath:@"@distinctUnionOfObjects.self"];
    NSLog(@"uniqueYears: %@", uniqueYears);


}];



}

Still not getting unique years..

Commutual answered 15/10, 2013 at 5:32 Comment(2)
possible duplicate of removing duplicates from array in objective cAnagnos
I tried that answer too Adam. no joy.Commutual
P
28

An simple way is to create an NSSet from the array with duplicates. The result is a set which by definition stores only the unique objects. Then using NSSet's -allObjects method to convert the NSSet back to an NSArray. The only downside is you lose the original ordering by converting to an NSSet.

NSArray *uniqueArray = [[NSSet setWithArray:duplicateArray] allObjects];

If you need to preserve the ordering and can require 10.7+, you can use an NSOrderedSet.

NSArray *uniqueArray = [[NSOrderedSet orderedSetWithArray:duplicateArray] array];

Edit:

Thanks to Mattt Thompson in the WWDC 2013 Session 228 - Hidden Gems in Cocoa and Cocoa Touch, there is another way without creating an intermediate set.

NSArray *uniqueArray = [duplicateArray valueForKeyPath:@"@distinctUnionOfObjects.self"]
Proconsul answered 15/10, 2013 at 5:38 Comment(2)
Andrew, thank you. I used your code (properly this time). The unordered set worked beautifully. Many thanks.Commutual
Also you can mention that "@distinctUnionOfObjects.self" don't preserve orderRummage
A
8

You can use the array's valueForKeyPath and set it to distinctUnionOfObjects.self.

NSArray *yearsArray = @[@"1943", @"1945", @"1948", @"1948", @"1948", @"1949"];
NSArray *uniqueYears = [yearsArray valueForKeyPath:@"@distinctUnionOfObjects.self"];
NSLog(@"uniqueYears: %@", uniqueYears);
Awad answered 15/10, 2013 at 5:39 Comment(1)
Thanks, @Rob, I just realized that I copied this code from one of my projects. Edited.Awad
W
2

You provided a NSLog:

unique: (
    (
    1941,
    1942,
    1943,
    1945,
    1948,
    1948,
    1948,
    1949
    ) 
) 

This is not an array of strings. This is an array with one object, which is, itself, an array. That suggests that yearStringArray has that same structure. Clearly your code (and the name of that variable) suggests you thought it should be otherwise.

You should either fix whatever created yearStringArray to actually create an array of strings, or change your code to reflect this structure of yearStringArray, e.g.,

for (yearString in yearStringArray[0]) 
{
    ....
}
Witham answered 15/10, 2013 at 6:48 Comment(1)
Thanks Rob, your answer, combined with Andrew's gave me the clue and solution.Commutual
P
1

Here is bug.

if (![processed containsObject:yearString] == NO)

You have to use

if ([processed containsObject:yearString] == NO)

or

if (![processed containsObject:yearString])
Parachronism answered 15/10, 2013 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.