How to turn an NSArray of strings into an array of unique strings, in the same order?

旧城冷巷雨未停 提交于 2019-11-29 21:26:17

My initial thought was that you could do:

NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
NSLog(@"%@", [a valueForKeyPath:@"@distinctUnionOfObjects.self"]);

But that does not maintain order. Therefore, you have to do it manually:

NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
NSMutableArray * unique = [NSMutableArray array];
NSMutableSet * processed = [NSMutableSet set];
for (NSString * string in a) {
  if ([processed containsObject:string] == NO) {
    [unique addObject:string];
    [processed addObject:string];
  }
}

I use an NSMutableSet for determining if I've already come across this entry before (as opposed to [unique containsObject:string], since a set will have O(1) lookup time, and an array has O(n) lookup time. If you're only dealing with a small number of objects, then this won't matter. However, if the source array is very large, then using the set to determine uniqueness may add a bit of a speed boost. (however, you should use Instruments to profile your code and see if it's necessary)

You could do like this:

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

This way, you also preserve the order!

I Think You can Do this With that

NSArray * uniqueArray = [[Yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

i hope this would help you

Hmm.. you could just use a loop ?

NSMutableArray *newarray = [[NSMutableArray alloc] init];
NSString *laststring = nil;
for (NSString *currentstring in oldarray) 
{
   if (![currentstring isEqualtoString:laststring]) [newarray addObject:currentstring];
   laststring = currentstring
}

Here's a nice category that defines a custom operator like @distinctUnionOfObjects, except it only works on strings and it will maintain their original order. Note: It does not sort the strings for you. It leaves intact only the first instance of whatever strings are repeated.

Usage:

#import "NSArray+orderedDistinctUnionOfStrings.h"
...
// if you feed it an array that has already been ordered, it will work as expected
NSArray *myArray = @[@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE"];
NSArray *myUniqueArray = [myArray valueForKeyPath:@"@orderedDistinctUnionOfStrings.self"];

Output:

myUniqueArray = ( "ONE", "TWO", "THREE" )

.h file:

#import <Foundation/Foundation.h>

@interface NSArray (orderedDistinctUnionOfStrings)

@end

.m file:

#import "NSArray+orderedDistinctUnionOfObjects.h"

@implementation NSArray (orderedDistinctUnionOfObjects)

- (id) _orderedDistinctUnionOfStringsForKeyPath:(NSString*)keyPath {
    NSMutableIndexSet *removeIndexes = [NSMutableIndexSet indexSet];

    for (NSUInteger i = 0, n = self.count; i < n; ++i) {
        if ([removeIndexes containsIndex:i]) {
            continue;
        }
        NSString *str1 = [[self objectAtIndex:i] valueForKeyPath:keyPath];

        for (NSUInteger j = i+1; j < n; ++j) {
            if ([removeIndexes containsIndex:j]) {
                continue;
            }
            id obj = [self objectAtIndex:j];
            NSString *str2 = [obj valueForKeyPath:keyPath];
            if ([str1 isEqualToString:str2]) {
                [removeIndexes addIndex:j];
            }
        }
    }

    NSMutableArray *myMutableCopy = [self mutableCopy];
    [myMutableCopy removeObjectsAtIndexes:removeIndexes];

    return [[NSArray arrayWithArray:myMutableCopy] valueForKeyPath:[NSString stringWithFormat:@"@unionOfObjects.%@", keyPath]];
}

@end

And here is an excellent read on how to generate your own operators, and demystifies (by a little bit) how this works: http://bou.io/KVCCustomOperators.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!