Как превратить NSArray из строк в массив уникальных строк, в том же порядке? - PullRequest
27 голосов
/ 18 ноября 2010

Если у вас есть NSArray из строк

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

Как бы превратить это в

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

.. где массив будет следовать тому же порядку, что и оригиналЯ думаю, что вы можете превратить массив в NSSet, чтобы получить уникальные элементы, но если вы превратите его обратно в массив, вы не гарантированно получите тот же порядок.

Ответы [ 5 ]

49 голосов
/ 18 ноября 2010

Первоначально я думал, что вы можете сделать:

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

Но это не поддерживает порядок.Следовательно, вы должны сделать это вручную:

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];
  }
}

Я использую NSMutableSet для определения того, встречал ли я эту запись ранее (в отличие от [unique containsObject:string], поскольку в наборе будет O(1) время поиска, а массив имеет время поиска O (n). Если вы имеете дело только с небольшим количеством объектов, то это не имеет значения. Однако, если исходный массив очень большой, используйтеустановка для определения уникальности может добавить некоторое повышение скорости (однако вы должны использовать инструменты для профилирования своего кода и проверки необходимости)

47 голосов
/ 27 декабря 2011

Вы можете сделать так:

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

Таким образом, вы также сохраните заказ!

6 голосов
/ 27 февраля 2013

Я думаю, вы можете сделать это с этим

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

Я надеюсь, что это поможет вам

0 голосов
/ 04 августа 2015

Вот хорошая категория, которая определяет пользовательский оператор , такой как @distinctUnionOfObjects, за исключением того, что он работает только со строками и будет поддерживать их порядок original .Примечание: он не сортирует строки для вас.Он оставляет без изменений только первый экземпляр любой повторяющейся строки.

Использование:

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

Вывод:

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

.h Файл:

#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

А вот отличное прочтение о том, как генерировать свои собственные операторы, и демонстрирует (немного), как это работает: http://bou.io/KVCCustomOperators.html

0 голосов
/ 18 ноября 2010

Хм .. Вы могли бы просто использовать петлю?

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