La meilleure façon de supprimer les valeurs en double ( NSString
) NSMutableArray
dans Objective-C?
Est-ce la manière la plus simple et la plus appropriée de le faire?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
La meilleure façon de supprimer les valeurs en double ( NSString
) NSMutableArray
dans Objective-C?
Est-ce la manière la plus simple et la plus appropriée de le faire?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Réponses:
Votre NSSet
approche est la meilleure si vous ne vous inquiétez pas de l'ordre des objets, mais encore une fois, si vous ne vous inquiétez pas de l'ordre, alors pourquoi ne les stockez-vous pas dans un NSSet
pour commencer?
J'ai écrit la réponse ci-dessous en 2009; en 2011, Apple a ajouté NSOrderedSet
iOS 5 et Mac OS X 10.7. Ce qui avait été un algorithme est maintenant composé de deux lignes de code:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
Si vous vous inquiétez de la commande et que vous utilisez iOS 4 ou une version antérieure, parcourez une copie du tableau:
NSArray *copy = [mutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
[mutableArray removeObjectAtIndex:index];
}
index--;
}
[copy release];
[NSOrderedSet orderedSetWithArray:array];
Vous pouvez ensuite récupérer un tableau via array = [orderedSet allObjects];
ou simplement utiliser NSOrderedSet
s au NSArray
lieu de.
[orderedSet allObjects]
par [orderedSet array]
!
NSArray
et devrions créer des temp NSMutableArray
. Dans votre exemple, vous travaillez vice versa
NSSet
) ou @Simon Whitaker lien empêchent ajouter avant doublon qui est de manière efficace?
Je sais que c'est une vieille question, mais il existe un moyen plus élégant de supprimer les doublons NSArray
si vous ne vous souciez pas de la commande .
Si nous utilisons des opérateurs d'objets du codage de valeurs clés, nous pouvons le faire:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Comme AnthoPak l'a également noté, il est possible de supprimer les doublons en fonction d'une propriété. Un exemple serait:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
pour supprimer les doublons par propriété d'un tableau d'objets personnalisés. Par exemple@distinctUnionOfObjects.name
Oui, l'utilisation de NSSet est une approche judicieuse.
Pour ajouter à la réponse de Jim Puls, voici une approche alternative pour supprimer les doublons tout en conservant l'ordre:
// Initialise a new, empty mutable array
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
C'est essentiellement la même approche que celle de Jim, mais copie les éléments uniques dans un nouveau tableau mutable plutôt que de supprimer les doublons de l'original. Cela le rend légèrement plus efficace dans le cas d'un grand tableau avec beaucoup de doublons (pas besoin de faire une copie de l'ensemble du tableau), et est à mon avis un peu plus lisible.
Notez que dans les deux cas, vérifier si un élément est déjà inclus dans le tableau cible (en utilisant containsObject:
dans mon exemple, ou indexOfObject:inRange:
dans celui de Jim) ne s'adapte pas bien aux grands tableaux. Ces vérifications s'exécutent en temps O (N), ce qui signifie que si vous doublez la taille du tableau d'origine, chaque vérification prendra deux fois plus de temps à s'exécuter. Puisque vous effectuez la vérification pour chaque objet du tableau, vous exécuterez également plus de ces vérifications plus coûteuses. L'algorithme global (le mien et celui de Jim) s'exécute en temps O (N 2 ), ce qui devient vite coûteux à mesure que le tableau d'origine se développe.
Pour ramener cela au temps O (N), vous pouvez utiliser a NSMutableSet
pour stocker un enregistrement des éléments déjà ajoutés au nouveau tableau, car les recherches NSSet sont O (1) plutôt que O (N). En d'autres termes, vérifier si un élément est membre d'un NSSet prend le même temps, quel que soit le nombre d'éléments dans l'ensemble.
Le code utilisant cette approche ressemblerait à ceci:
NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];
for (id obj in originalArray) {
if (![seen containsObject:obj]) {
[unique addObject:obj];
[seen addObject:obj];
}
}
Cela semble néanmoins un peu inutile; nous sommes toujours en train de générer un nouveau tableau lorsque la question a clairement indiqué que le tableau d'origine est mutable, nous devrions donc être en mesure de le déduper en place et d'économiser de la mémoire. Quelque chose comme ça:
NSMutableSet *seen = [NSMutableSet set];
NSUInteger i = 0;
while (i < [originalArray count]) {
id obj = [originalArray objectAtIndex:i];
if ([seen containsObject:obj]) {
[originalArray removeObjectAtIndex:i];
// NB: we *don't* increment i here; since
// we've removed the object previously at
// index i, [originalArray objectAtIndex:i]
// now points to the next object in the array.
} else {
[seen addObject:obj];
i++;
}
}
MISE À JOUR : Yuri Niyazov a souligné que ma dernière réponse s'exécute en fait en O (N 2 ) parce que removeObjectAtIndex:
probablement en O (N).
(Il dit "probablement" parce que nous ne savons pas avec certitude comment il est implémenté; mais une implémentation possible est qu'après avoir supprimé l'objet à l'index X, la méthode boucle ensuite sur chaque élément de l'index X + 1 au dernier objet du tableau , en les déplaçant vers l'index précédent. Si tel est le cas, il s'agit bien de la performance O (N).)
Alors que faire? Ça dépend de la situation. Si vous avez un grand tableau et que vous ne vous attendez qu'à un petit nombre de doublons, la déduplication sur place fonctionnera très bien et vous évitera d'avoir à créer un tableau en double. Si vous avez un tableau dans lequel vous vous attendez à beaucoup de doublons, la création d'un tableau séparé et déduppé est probablement la meilleure approche. Ce qu'il faut retenir ici, c'est que la notation big-O ne décrit que les caractéristiques d'un algorithme, elle ne vous dira pas définitivement ce qui est le mieux pour une circonstance donnée.
Si vous ciblez iOS 5+ (ce qui couvre tout le monde iOS), meilleure utilisation NSOrderedSet
. Il supprime les doublons et conserve l'ordre de votre NSArray
.
Fais juste
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
Vous pouvez maintenant le reconvertir en un NSArray unique
NSArray *uniqueArray = orderedSet.array;
Ou utilisez simplement le orderSet car il a les mêmes méthodes qu'un NSArray comme objectAtIndex:
, firstObject
et ainsi de suite.
Un chèque d'adhésion avec contains
est encore plus rapide sur le NSOrderedSet
que ce serait sur uneNSArray
Pour plus d'informations, consultez la référence NSOrderedSet
Disponible dans OS X v10.7 et versions ultérieures.
Si vous êtes inquiet pour la commande, bonne façon de faire
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];
Voici le code de suppression des valeurs en double de NSArray dans l'ordre.
besoin d'ordre
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
ou pas besoin de commande
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
Ici, j'ai supprimé les valeurs de nom en double de mainArray et stocké le résultat dans NSMutableArray (listOfUsers)
for (int i=0; i<mainArray.count; i++) {
if (listOfUsers.count==0) {
[listOfUsers addObject:[mainArray objectAtIndex:i]];
}
else if ([[listOfUsers valueForKey:@"name" ] containsObject:[[mainArray objectAtIndex:i] valueForKey:@"name"]])
{
NSLog(@"Same object");
}
else
{
[listOfUsers addObject:[mainArray objectAtIndex:i]];
}
}
Notez que si vous avez un tableau trié, vous n'avez pas besoin de vérifier tous les autres éléments du tableau, juste le dernier élément. Cela devrait être beaucoup plus rapide que de vérifier tous les éléments.
// sortedSourceArray is the source array, already sorted
NSMutableArray *newArray = [[NSMutableArray alloc] initWithObjects:[sortedSourceArray objectAtIndex:0]];
for (int i = 1; i < [sortedSourceArray count]; i++)
{
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
{
[newArray addObject:[tempArray objectAtIndex:i]];
}
}
Il semble que les NSOrderedSet
réponses qui sont également suggérées nécessitent beaucoup moins de code, mais si vous ne pouvez pas utiliser un NSOrderedSet
pour une raison quelconque et que vous avez un tableau trié, je pense que ma solution serait la plus rapide. Je ne sais pas comment cela se compare à la vitesse des NSOrderedSet
solutions. Notez également que mon code est en cours de vérification avec isEqualToString:
, donc la même série de lettres n'apparaîtra pas plus d'une fois newArray
. Je ne sais pas si les NSOrderedSet
solutions supprimeront les doublons en fonction de la valeur ou de l'emplacement de la mémoire.
Mon exemple suppose qu'il sortedSourceArray
contient juste NSString
s, juste NSMutableString
s ou un mélange des deux. Si à la sortedSourceArray
place contient juste NSNumber
s ou juste NSDate
s, vous pouvez remplacer
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
avec
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
et cela devrait fonctionner parfaitement. Si sortedSourceArray
contient un mélange de NSString
s, NSNumber
s et / ou NSDate
s, il plantera probablement.
Il existe un opérateur d'objets KVC qui offre une solution plus élégante. uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Voici une catégorie NSArray .
Une autre façon simple d'essayer qui n'ajoutera pas de valeur en double avant d'ajouter un objet dans le tableau: -
// Supposons que mutableArray est alloué et initialisé et contient une valeur
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
Supprimer les valeurs en double de NSMutableArray dans Objective-C
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
Voici le code de suppression des valeurs en double de NSMutable Array. .il fonctionnera pour vous. myArray est votre matrice mutable dont vous souhaitez supprimer les valeurs en double.
for(int j = 0; j < [myMutableArray count]; j++){
for( k = j+1;k < [myMutableArray count];k++){
NSString *str1 = [myMutableArray objectAtIndex:j];
NSString *str2 = [myMutableArray objectAtIndex:k];
if([str1 isEqualToString:str2])
[myMutableArray removeObjectAtIndex:k];
}
} // Now print your array and will see there is no repeated value
utilisez simplement ce code simple:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
puisque nsset n'autorise pas les valeurs dupliquées et que tous les objets retournent un tableau
NSOrderedSet
insteed of NSSet
.