web-dev-qa-db-fra.com

Le moyen le plus rapide de vérifier si un tableau contient les mêmes objets qu'un autre tableau

Le but est de comparer deux tableaux au fur et à mesure et de vérifier s’ils contiennent les mêmes objets (le plus rapidement possible - il y a beaucoup d’objets dans les tableaux). Les tableaux ne peuvent pas être vérifiés avec isEqual: car ils sont triés différemment.

J'ai déjà essayé la solution publiée ici ( https://stackoverflow.com/a/1138417 - voir dernier extrait de code du message de Peter Hosey). Mais cela ne fonctionne pas avec des tableaux triés différemment.

Le code que j'utilise maintenant est le suivant:

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;
    for (id objectInArray1 in array1) {
        BOOL objectFoundInArray2 = NO;
        for (id objectInArray2 in array2) {
            if ([objectInArray1 isEqual:objectInArray2]) {
                objectFoundInArray2 = YES;
                break;
            }
        }
        if (!objectFoundInArray2) {
            bothArraysContainTheSameObjects = NO;
            break;
        }
    }

    return bothArraysContainTheSameObjects;
}

Cela fonctionne, mais ce sont deux énumérations rapides imbriquées. Y at-il un moyen de faire une comparaison plus rapide?

24
FrankZp

Selon votre code, vous respectez le même nombre d'éléments et chaque objet du premier tableau doit figurer dans le second tableau et inversement.

Le moyen le plus rapide serait de trier le tableau et de le comparer.

Ex:

NSArray *array1=@[@"a",@"b",@"c"];
NSArray *array2=@[@"c",@"b",@"a"];

array1=[array1 sortedArrayUsingSelector:@selector(compare:)];
array2=[array2 sortedArrayUsingSelector:@selector(compare:)];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both have same elements");
}
else{
    NSLog(@"both having different elements");
}
41
Anoop Vaidya

Que diriez-vous de convertir les deux tableaux en ensembles et de les comparer.

NSSet *set1 = [NSSet setWithArray:arr1];
NSSet *set2 = [NSSet setWithArray:arr2];

Comparez les deux en utilisant 

if([set1 isEqualToSet:set2]) {

}
12
Shashank

Essayé de faire fonctionner la réponse acceptée, mais ce n'était pas tout à fait la meilleure solution pour ma situation.

J'ai trouvé cette réponse et tout le mérite revient à @joel kravets pour la méthode.

Fondamentalement, le tri à l'aide d'un comparateur vous permet de trier plus facilement des objets - d'où le problème que je rencontrais lorsque j'essayais d'utiliser la solution ci-dessus. 

NSArray * array1 = [NSArray arrayWithArray:users];
NSArray * array2 = [NSArray arrayWithArray:threadUsers];

id mySort = ^(BUser * user1, BUser * user2){
    return [user1.name compare:user2.name];
};

array1 = [array1 sortedArrayUsingComparator:mySort];
array2 = [array2 sortedArrayUsingComparator:mySort];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both are same");
}
else{
    NSLog(@"both are different");
}

Auparavant, j'avais essayé d'utiliser d'autres réponses comme celles ci-dessus, en utilisant break pour passer en boucle, mais au final, cette réponse est apparue la plus facile, probablement en raison de sa rapidité et, à la fin, de la déclaration if permettant de placer du code en fonction de si elles sont identiques ou différentes.

Merci à Anoop de m'avoir mis sur la bonne voie et à Joel de m'aider à resserrer son efficacité

3
simon_smiley

Utilisez includesObject: method au lieu d'itérer l'intégralité du tableau.

NSArray *array;
array = [NSArray arrayWithObjects: @"Nicola", @"Margherita",                                       @"Luciano", @"Silvia", nil];
if ([array containsObject: @"Nicola"]) // YES
  {
    // Do something
  }

comme ça

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;

    for (id objectInArray1 in array1) {

        if (![array2 containsObject:objectInArray1])
        {
            bothArraysContainTheSameObjects = NO;
            break;
        }

    }

    return bothArraysContainTheSameObjects;
}
3
Pushpak Narasimhan
NSArray *filtered = [someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someParamter == %@", paramValue]]];
if (filtered.count) {

}

le principal avantage est que vous pouvez l’utiliser pour n’importe quel type d’objet: personnalisé, système, NSDictionary. Par exemple, je dois savoir si la pile de mon UINavigationController contient MySearchResultsVC et MyTopMenuItemsVC ou non:

    NSArray *filtered = [self.navigationController.viewControllers filteredArrayUsingPredicate:
                                     [NSPredicate predicateWithFormat:@"class IN %@",
                                      [NSArray arrayWithObjects:
                                       [MySearchResultsVC class],
                                       [MyTopMenuItemsVC class],
                                       nil]]];
if (filtered) {
/* ok, now we can handle it! */
}
1
iiFreeman

De cette façon, la complexité est O (N ^ 2). Si vous suivez cette approche, vous ne pourrez pas le faire avec une complexité inférieure. Au lieu de cela, vous pouvez le faire avec O (N log (N)) si vous triez les deux tableaux, puis les comparez. De cette façon, après les avoir triés, vous le ferez en utilisant isEqualToArray: dans d’autres N opérations.

1
Ramy Al Zuhouri
[docTypes containsObject:@"Object"];

Cela fonctionnera pour votre req. Dès que possible, il retournera une valeur booléenne.

1
Madhu

Si vous voulez vérifier si les deux tableaux contiennent les mêmes doublons, utilisez simplement NSCountedSet. C'est comme un NSSet, mais chaque objet de l'ensemble a aussi un compte qui vous dit à quelle fréquence il a été ajouté. Alors

BOOL same = (array1.count == array2.count);
if (same && array.count > 0)
{
    NSCountedSet* set1 = [[NSCountedSet alloc] initWithArray:array1];
    NSCountedSet* set2 = [[NSCountedSet alloc] initWithArray:array2];
    same = ([set1 isEqual: set2]);
}

Quelle que soit la façon dont vous le faites, cela prendra beaucoup de temps. Vous pouvez donc envisager des cas spéciaux pouvant être traités plus rapidement. Ces tableaux sont-ils généralement identiques ou presque, ou est-il vrai 99% du temps qu'ils sont différents et 99% du temps, un élément aléatoire de array1 n'est pas dans array2? Les tableaux sont-ils souvent triés? Dans ce cas, vous pouvez vérifier s'il y a des objets identiques dans des positions identiques, puis ne considérer que les objets qui ne sont pas identiques. Si un tableau contient les objets a, b, c, d, e et que l'autre contient a, b, x, d, y, il vous suffit de comparer le tableau [c, e] et [x, y]. 

1
gnasher729

Je sais qu'il est tard mais je veux juste partager ce que j'ai fait ..

NSString *stringArr1 = [NSString stringWithFormat:@"%@", array1];
NSString *stringArr2 = [NSString stringWithFormat:@"%@", array2];

if ([stringArr1 isEqual: stringArr2])
    NSLog(@"identical");
else
    NSLog(@"not");

c'est comme comparer "@ [@ 1, @ 2, @ 3, @ 4]" == "[@ 3, @ 2, @ 1, @ 4]" .. ce qui est évidemment faux.

0
0yeoj