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

前端 未结 5 1984
我在风中等你
我在风中等你 2020-12-23 17:34

If you have an NSArray of strings

{ @\"ONE\", @\"ONE\", @\"ONE\", \"TWO\", @\"THREE\", @\"THREE\" }

How would I turn that into

<         


        
相关标签:
5条回答
  • 2020-12-23 17:42

    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
    }
    
    0 讨论(0)
  • 2020-12-23 17:55

    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

    0 讨论(0)
  • 2020-12-23 17:57

    You could do like this:

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

    This way, you also preserve the order!

    0 讨论(0)
  • 2020-12-23 17:58

    I Think You can Do this With that

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

    i hope this would help you

    0 讨论(0)
  • 2020-12-23 17:59

    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)

    0 讨论(0)
提交回复
热议问题