2009-05-25 13 views
7

NSArray nützliche Methoden hat Objekte für bestimmte IndizesErhalten NSIndexSet von NSArray

// To find objects by indexes 
- (id)objectAtIndex:(NSUInteger)index 
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes 

// To find index by object 
- (NSUInteger)indexOfObject:(id)anObject 

jedoch zu finden, ich will NSIndexSet (mehrere Indizes) erhalten für bestimmte Objekte. Etwas wie:

- (NSIndexSet *)indexesOfObjects:(NSArray *)objects 

Diese Methode existiert nicht für NSArray. Fehle ich etwas? Kennt jemand eine andere Standardmethode? Ansonsten muss ich dies als Kategoriemethode schreiben.

Antwort

6

Es könnte nützlich sein implementieren es einen Satz mit den Objekten zu spezifizieren zu finden, wie zB:

- (NSIndexSet *) indicesOfObjectsInSet: (NSSet *) set 
{ 
    if ([set count] == 0) 
     return ([NSIndexSet indexSet]); 

    NSMutableIndexSet * indices = [NSMutableIndexSet indexSet]; 

    NSUInteger index = 0; 
    for (id obj in self) 
    { 
     if ([set containsObject: obj]) 
      [indices addIndex: index]; 

     index++; 
    } 

    return ([[indices copy] autorelease]); 
} 

Dies erfordert jedes Objekt im Array besuchen, aber zumindest tut nur so einmal und macht Gebrauch der schnellen Aufzählung dabei. Die Verwendung eines NSSet und das Testen jedes Objekts im Array mit diesem Set ist ebenfalls viel schneller als das Testen für die Aufnahme in ein Array.

Es gibt eine mögliche Optimierung hier, aber es wäre in dem Fall zu brechen, wo ein einzelnes Objekt in der Empfangsarray mehrere Male gespeichert ist:

if ([set containsObject: obj]) 
{ 
    [indices addIndex: index]; 
    if ([indices count] == [set count]) 
     break; 
} 

Auf diese Weise, wenn Sie ein 20'000-Artikel scannen Array für zwei Objekte und sie sind beide innerhalb der ersten zehn, können Sie vermeiden, die anderen 19'990 Objekte im Array zu scannen. Wie gesagt, das hilft nicht, wenn das Array Duplikate enthält, weil es stoppt, sobald es 2 Indizes gefunden hat (auch wenn beide auf das gleiche Objekt zeigen).

Nachdem ich das gesagt habe, stimme ich Mikes Kommentar oben zu. Die Chancen stehen gut, dass Sie sich für etwas Schmerz zur Optimierungszeit bereit machen. Es kann sich lohnen, über verschiedene Datentypen nachzudenken; Zum Beispiel, während NSArray die logischste Wahl für einen einfachen, flachen Container ist, ist es besser, stattdessen einen NSSet zu verwenden, wenn Sie die Bestellinformationen nicht benötigen; Dies hat den zusätzlichen Vorteil, dass das gleiche Objekt (berechnet unter Verwendung von -isEqual:) nicht zweimal gespeichert wird. Wenn Sie die Duplikate verfolgen möchten, aber keine Sortierung benötigen, können Sie NSCountedSet verwenden, das sich wie NSSet verhält, außer dass es verfolgt, wie oft jedes Objekt hinzugefügt/entfernt wurde, ohne Duplikate zu speichern.

+2

+1 Nur ein kleiner Hinweis: sowohl "Indizes" als auch "Indizes" sind in Englisch korrekt, aber Cocoa verwendet immer "Indizes", daher ist es besser, zumindest für den Methodennamen in dieser Terminologie zu bleiben. –

1

Sie müssen Ihre eigene Kategorie implementieren, soweit ich sehen kann.

+2

Beachten Sie jedoch, dass diese Methode ein starkes Zeichen für einen Konstruktionsfehler ist. -indexOfObject: Durchsucht jedes Objekt im Array und wird daher für ein großes Array oder mehrere Suchvorgänge ziemlich langsam. Überdenken Sie Ihre Datenstrukturen für etwas Sinnvolleres. –

13

Neuere NSArray-Versionen (OSX 10.6 und iOS 4) bieten die indexesOfObjectsPassingTest:-Methode.

NSIndexSet *indexesOfObjects = [[array1 indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 
    return [array2 containsObject:obj]; 
}]; 
Verwandte Themen