2012-05-06 12 views
29

Ho due NSArrays:oggetti Sottrarre in uno NSArray da un altro array

NSArray *wants = [NSArray arrayWithObjects: 
        @"apples", 
        @"oranges", 
        @"pineapple", 
        @"mango", 
        @"strawberries", 
        nil]; 
NSArray *needs = [NSArray arrayWithObjects: 
        @"apples", 
        @"pineapple", 
        @"strawberries", 
        nil]; 

e voglio XOR loro. Qualcosa di simile wants - needs in modo che quello che ho lasciato è

[NSArray arrayWithObjects: 
@"oranges", 
@"mango", 
nil]; 

Io normalmente passare attraverso alcuni looping pesante, ma sono sicuro che ci sia un modo più pratico. Cosa dovrei fare invece?

risposta

58

Qualcosa di simile?

NSMutableArray *array = [NSMutableArray arrayWithArray:wants]; 
[array removeObjectsInArray:needs]; 
+1

Non si verifica un arresto anomalo se le esigenze contengono oggetti che non esistono nei desideri? – TompaLompa

+3

@TompaLompa No, non si blocca. Dai documenti di NSMutableArray: 'Se l'array ricevente non contiene oggetti in otherArray, il metodo non ha alcun effetto (sebbene debba sostenere l'overhead della ricerca dei contenuti). ' – highlycaffeinated

+0

Questo NON è un XOR, come se il bisogno contenga un oggetto che vuole no, il risultato non conterrà quell'oggetto. –

8

risposta di Kirby va bene, ma: se non vi interessa circa l'ordine degli elementi negli array, si dovrebbe utilizzare set, invece. Se l'ordine è importante, è possibile considerare NSOrderedSet. È possibile utilizzare lo -minusSet: o, per quest'ultimo, i metodi -minusOrderedSet:.

+0

Questa è sicuramente la strada da percorrere. Immagino che l'ordine non sia importante in questo esempio, ma anche se lo è, gli insiemi sono altamente ottimizzati per questo tipo di comportamento. –

+1

Si noti che 'NSOrderedSet' è disponibile solo in OSX ≥ 10.7 e iOS ≥ 5.0. –

0

Try This:

NSArray *NSArray_XOR(NSArray *arr1, NSArray *arr2) 
{ 
    NSMutableArray *results = [NSMutableArray array]; 

    for (int i = 0; i < arr1.count; i++) { 
     id obj = [arr1 objectAtIndex:i]; 

     if (![arr2 containsObject:obj]) 
      [results addObject:obj]; 
    } 

    for (int i = 0; i < arr2.count; i++) { 
     id obj = [arr2 objectAtIndex:i]; 

     if (![arr1 containsObject:obj]) 
      [results addObject:obj]; 
    } 

    // make a unmutable copy of the array. 
    return [NSArray arrayWithArray:results]; 
} 
+3

Non ho fatto down, ma questo algoritmo è almeno O (n^2) quando dovrebbe essere molto più semplice. – dreamlax

+1

Sì, probabilmente non è il modo migliore. – jpswain

2

Date due ipotesi: che l'ordine non è importante (o può essere ripristinato - ad esempio, se gli array sono ordinati ora) * e che nessuna voce appare più di una volta in entrambe le array (sebbene sia possibile utilizzare un set conteggiato per questo), un set potrebbe essere una buona scelta.

Il XOR (rigorosamente, la differenza simmetrica) di due set è l'unione meno l'intersezione:

NSMutableSet * unioned = [NSMutableSet setWithArray:wants]; 
[unioned unionSet:[NSSet setWithArray:needs]]; 
NSMutableSet * intersection = [NSMutableSet setWithArray:needs]; 
[intersection intersectSet:[NSSet setWithArray:wants]]; 

[unioned minusSet:intersection]; 

* Se l'ordine è importante, è possibile utilizzare NSOrderedSet.

7

Come utilizzare i predicati?

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", needs]; 
NSArray *wants_needs = [wants filteredArrayUsingPredicate:predicate];