web-dev-qa-db-fra.com

Comment transformer un tableau NSArray de chaînes en tableau unique, dans le même ordre?

Si vous avez un tableau NSArray de chaînes

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

Comment pourrais-je transformer cela en

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

..where le tableau suit le même ordre que l'original. Je pense que vous pouvez transformer un tableau en un NSSet pour obtenir des éléments uniques, mais si vous le reconvertissez en un tableau, vous n'êtes pas sûr d'obtenir le même ordre.

27
cannyboy

Ma pensée initiale était que vous pouviez faire:

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

Mais cela ne maintient pas l'ordre. Par conséquent, vous devez le faire manuellement:

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

J'utilise un NSMutableSet pour déterminer si j'ai déjà rencontré cette entrée auparavant (par opposition à [unique containsObject:string], puisqu'un ensemble aura le temps de recherche O(1), et un tableau a O(n) temps de recherche. Si le tableau source est très grand, l’utilisation de cet ensemble pour déterminer l’unicité peut ajouter un peu de valeur. accélération de la vitesse (cependant, vous devriez utiliser Instruments pour profiler votre code et voir si c'est nécessaire)

49
Dave DeLong

Vous pourriez faire comme ça:

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

De cette façon, vous conservez également l'ordre!

47
Santhosbaala RS

Je pense que tu peux faire ça avec ça

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

j'espère que cela pourrait vous aider

6
umer sufyan

Voici une catégorie Nice qui définit un opérateur personnalisé like @distinctUnionOfObjects, sauf que cela ne fonctionne que sur les chaînes et qu'il conservera leur ordre original . Remarque: il ne trie pas les chaînes pour vous. Cela ne laisse intacte que la première instance des chaînes qui sont répétées.

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

Sortie:

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

fichier .h:

#import <Foundation/Foundation.h>

@interface NSArray (orderedDistinctUnionOfStrings)

@end

fichier .m:

#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

Et voici une excellente lecture sur la façon de générer vos propres opérateurs, et démystifie (un peu) son fonctionnement: http://bou.io/KVCCustomOperators.html

0
jperl

Hmm .. vous pouvez simplement utiliser une boucle?

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