Подтвердить что ты не робот

Как превратить NSArray строк в массив уникальных строк в том же порядке?

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

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

Как мне превратить это в

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

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

4b9b3361

Ответ 1

Моя первоначальная мысль заключалась в том, что вы могли бы сделать:

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) поиск Если вы имеете дело с небольшим количеством объектов, это не имеет значения. Однако, если исходный массив очень велик, то использование набора для определения уникальности может добавить немного ускорения скорости (однако, вы должны использовать Инструменты для профилирования своего кода и посмотреть, если это необходимо)

Ответ 2

Вы можете сделать следующее:

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

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

Ответ 3

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

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

Надеюсь, это поможет вам.

Ответ 4

Хм.. вы могли бы просто использовать цикл?

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

Ответ 5

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

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

#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