2013-02-18 14 views
18

Ziel ist es, zwei Arrays als zu vergleichen und zu prüfen, ob sie die gleichen Objekte enthalten (so schnell wie möglich - es gibt viele Objekte in den Arrays). Die Arrays können nicht mit isEqual: überprüft werden, da sie unterschiedlich sortiert sind.Schnellste Möglichkeit zu überprüfen, ob ein Array die gleichen Objekte eines anderen Arrays enthält

Ich habe bereits die hier gepostete Lösung ausprobiert (https://stackoverflow.com/a/1138417 - siehe letzten Codeausschnitt des Posts von Peter Hosey). Dies funktioniert jedoch nicht mit unterschiedlich sortierten Arrays.

Der Code, den ich jetzt bin mit ist die folgende:

+ (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; 
} 

Dies funktioniert, aber das sind zwei ineinander geschachtelten schnell Aufzählungen. Gibt es eine Möglichkeit, einen schnelleren Vergleich durchzuführen?

+2

Müssen Sie auch überprüfen, ob die Anzahl der übereinstimmenden Objekte gleich ist? Zum Beispiel, wenn Array 1 2 Instanzen von X hat, aber Array 2 nur 1 hat, dann scheitert es? – borrrden

+0

Ja, dies sollte auch verifiziert werden. – FrankZp

+3

In diesem Fall haben Sie keine andere Wahl, als beide zu sortieren und zu vergleichen. – borrrden

Antwort

39

Wie pro Ihren Code, Sie sind streng gleiche Anzahl von Elementen und jedes Objekt der ersten Anordnung sollte es in der zweiten Reihe sein und umgekehrt.

Der schnellste Weg wäre, sowohl das Array zu sortieren als auch zu vergleichen.

Ex:

NSArray *[email protected][@"a",@"b",@"c"]; 
NSArray *[email protected][@"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"); 
} 
+0

Credits gehen auch nach borrrden (siehe Kommentare zum ursprünglichen Post). – FrankZp

+0

Oh ja, ich habe gerade bemerkt ... ähnliche Gedanken. –

+0

@PushpakNarasimhan: Suchen ??? meinst du mit zwei Arrays vergleichen? –

-4

Ich denke, das tun wird:

[array1 isEqualToArray:array2]; 

kehrt Bool;

+2

NSArray-Klassenreferenz sagt für 'isEqualToArray:': "Zwei Arrays haben gleiche Inhalte, wenn sie jeweils die gleiche Anzahl von Objekten und Objekten an einem bestimmten Index in jedem Array enthalten, die den isEqual: test erfüllen." - Da die Arrays unterschiedlich sortiert sind, nehme ich an, dass die Methode NO zurückgibt, auch wenn sich die gleichen Objekte in beiden Arrays befinden, aber mit einer anderen Sortierung. – FrankZp

1

Auf diese Weise ist die Komplexität O (N^2), wenn Sie diesem Ansatz folgen, können Sie es nicht mit einer geringeren Komplexität tun. Stattdessen können Sie es mit O (N log (N)) tun, wenn Sie beide Arrays sortieren und dann vergleichen. Auf diese Weise werden sie nach dem Sortieren mit isEqualToArray: in anderen N-Operationen ausgeführt.

+0

Ich nehme an, dass ich beide Arrays sortieren muss? Wenn das erste Array unsortiert ist und das andere Array sortiert ist, nehme ich an, dass 'isEqualToArray' nicht YES zurückgibt, wenn die gleichen Objekte enthalten sind? (edit: hab gerade gesehen, dass borrrden das als kommentar zum ersten post hinzugefügt hat;)) – FrankZp

+0

Sorry, ich dachte das man sortiert wurde, repariere es. –

11

Wie wäre es, wenn Sie beide Arrays in Sets konvertieren und vergleichen?

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

Vergleichen Sie die beiden

if([set1 isEqualToSet:set2]) { 

} 
+2

Ich habe auch über diesen Weg nachgedacht, aber es wird nicht funktionieren, wenn die Bedingungen meines Kommentars gültig sind. – borrrden

+0

U war ein Schritt voraus @borrden :) – Shashank

+0

Dies ist die richtige Antwort, wenn Sie nicht über mehrere Instanzen des gleichen Objekts in einem Array betroffen sind. –

1
[docTypes containsObject:@"Object"]; 

Es werden Werke für Ihre req verwenden. So schnell wie schnell wird es booleschen Wert dafür zurückgeben.

3

Verwenden Sie die Methode "containsObject:", anstatt das gesamte Array zu durchlaufen.

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

wie diese

+ (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; 
} 
+1

'containsObject' 'Komplexität ist oft im schlimmsten Fall linear (selbst wenn die Arrays sortiert sind), so dass dies nicht asymptotisch effizienter ist als die beiden verschachtelten schnellen Enumerationen. –

+0

@ DanielMartín Hmmm ich stimme zu. Und wie Borrrden richtig sagte, ist nur die Option zu sortieren und zu vergleichen. –

+1

Dieser Ansatz kann jedoch möglicherweise viel früher beendet werden, wenn es sehr wahrscheinlich ist, dass Arrays ungleich sind. –

1
NSArray *filtered = [someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someParamter == %@", paramValue]]]; 
if (filtered.count) { 

} 

die Haupt-plus ist man es für jede Art von Objekten verwenden können: individuelle, System, NSDictionary. zum Beispiel muss ich wissen, ist Stack meine UINavigationController ist enthält MySearchResultsVC und MyTopMenuItemsVC oder nicht:

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! */ 
} 
2

Wenn Sie überprüfen wollen, ob die beiden Arrays die gleichen Duplikate, nur verwenden NSCountedSet enthalten. Es ist wie ein NSSet, aber jedes Objekt in dem Set hat auch eine Zählung, die sagt, wie oft es hinzugefügt wurde.So

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

Egal, wie Sie es tun, wird diese Zeit in Anspruch nehmen, so dass Sie vielleicht überlegen, ob es spezielle Fälle, die schneller gehandhabt werden können. Sind diese Arrays normalerweise gleich oder fast identisch oder ist es zu 99% der Zeit wahr, dass sie unterschiedlich sind und dass 99% der Zeit ein zufälliges Element von Array1 nicht in Array2 ist? Sind die Arrays oft sortiert? In diesem Fall könnten Sie überprüfen, ob identische Objekte an identischen Positionen vorhanden sind, und dann nur die Objekte berücksichtigen, die nicht identisch sind. Wenn ein Array die Objekte a, b, c, d, e enthält und das andere a, b, x, d, y enthält, müssen Sie nur das Array [c, e] gegenüber [x, y] vergleichen.

2

Versucht, die akzeptierte Antwort funktioniert zu bekommen, aber es war nicht ganz die beste Lösung für meine Situation.

Ich fand this answer und alle Kredite gehen an @joel kravets für die Methode.

Grundsätzlich ermöglicht die Sortierung mit einem Komparator eine leichtere Sortierung unter Verwendung von Objekten - daher das Problem, mit dem ich konfrontiert war, als ich versuchte, die obige Lösung zu verwenden.

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"); 
} 

Zuvor hatte ich versucht, andere Antworten oben, wie sie zu verwenden, Pause, um durch Schleifen zu gehen, aber am Ende dieser Antwort kam am einfachsten wahrscheinlich seine Geschwindigkeit wegen und auch, dass am Ende haben wir die if-Anweisung uns erlauben, Code abhängig davon zu setzen, ob sie gleich oder verschieden sind.

Dank Anoop für mich auf dem richtigen Weg und Joel immer mir zu helfen, die Effizienz der es

0

Ich weiß, es ist spät, aber ich möchte nur teilen zu straffen, was ich tat ..

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

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

Das ist genau wie beim Vergleich "@ [@ 1, @ 2, @ 3, @ 4]" == "[@ 3, @ 2, @ 1, @ 4]" .. was offensichtlich falsch ist.

Verwandte Themen