2012-05-06 57 views
29

Mam dwa NSArrays:obiekty Odejmowanie w jednym NSArray z innej tablicy

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

I chcę je XOR. Coś jak wants - needs tak, że to co mi pozostało to

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

bym normalnie przejść przez niektórych ciężkich pętli, ale jestem pewien, że jest bardziej praktyczny sposób. Co powinienem zamiast tego zrobić?

Odpowiedz

58

Coś takiego?

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

Czy to zderzenie, jeśli potrzebuje, zawiera przedmioty, które nie istnieją? – TompaLompa

+3

@ TompaLompa Nie, to się nie psuje. Z dokumentacji NSMutableArray: 'Jeśli tablica odbierająca nie zawiera obiektów w otherArray, metoda ta nie ma żadnego efektu (chociaż nakłada się na nią przeszukiwanie zawartości). ' – highlycaffeinated

+0

To NIE jest XOR, tak jakby potrzeby zawierały obiekt, który chce nie, wynik nie będzie zawierał tego obiektu. –

8

odpowiedź Kirby jest w porządku, ale: jeśli nie dbają o kolejności elementów w tablicach, powinno być zamiast przy użyciu zestawów. Jeśli zamówienie jest ważne, możesz wziąć pod uwagę NSOrderedSet. Można użyć metod -minusSet: lub dla tych ostatnich -minusOrderedSet:.

+0

To zdecydowanie jest droga. Wyobrażam sobie, że kolejność nie jest ważna w tym przykładzie, ale nawet jeśli tak jest, zestawy są wysoce zoptymalizowane pod kątem tego rodzaju zachowania. –

+1

Należy zauważyć, że 'NSOrderedSet' jest dostępny tylko w OSX ≥ 10.7 i iOS ≥ 5.0. –

0

Spróbuj to:

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

Nie spadłem, ale ten algorytm jest co najmniej O (n^2), kiedy powinno być znacznie prostsze. – dreamlax

+1

Tak, prawdopodobnie nie jest to najlepszy sposób. – jpswain

2

Biorąc pod uwagę dwa założenia: że kolejność nie jest ważna (lub może zostać przywrócona - na przykład wtedy, gdy tablice są sortowane teraz) * i że żadna pozycja pojawia się więcej niż jeden raz w którymkolwiek array (chociaż można do tego użyć zestawu zliczanego), zestaw może być dobrym wyborem.

XOR (ściśle, różnica symetryczna) dwóch zestawów jest sumą minus przecięcie:

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

[unioned minusSet:intersection]; 

* Jeśli kolejność jest istotna, można użyć NSOrderedSet.

7

Co powiesz na temat używania predykatów?

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