How do I get unique values from an array

2019-04-09 20:15发布

问题:

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..

回答1:

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"]


回答2:

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);


回答3:

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]) 
{
    ....
}


回答4:

Here is bug.

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

You have to use

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

or

if (![processed containsObject:yearString])