2012-05-06 4 views
29

У меня есть два NSArrays:объектов Вычитание в одном NSArray из другого массива

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

И я хочу XOR их. Что-то вроде wants - needs так, что я оставил это

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

Я обычно иду через какое-то тяжелое зацикливание, но я уверен, что есть более практичный способ. Что мне делать вместо этого?

ответ

58

Что-то вроде этого?

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

Wont that crash if needs содержит объекты, которые не существуют в желаниях? – TompaLompa

+3

@ TompaLompa Нет, это не сбой. Из документов NSMutableArray: 'Если принимающий массив не содержит объектов в otherArray, метод не имеет никакого эффекта (хотя на него налагаются накладные расходы на поиск содержимого). – highlycaffeinated

+0

Это НЕ XOR, как будто в нем содержится объект, который не хочет, результат не будет содержать этот объект. –

8

ответ Кирби это хорошо, но: если вы не заботитесь о порядке элементов в массивах, вы должны использовать наборы вместо. Если заказ важен, вы можете рассмотреть NSOrderedSet. Вы можете использовать -minusSet: или, для последнего, -minusOrderedSet: методов.

+0

Это, безусловно, путь. Я предполагаю, что порядок не важен в этом примере, но даже если это так, наборы очень оптимизированы для такого поведения. –

+1

Обратите внимание, что 'NSOrderedSet' доступен только в OSX ≥ 10.7 и iOS ≥ 5.0. –

0

Попробуйте:

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

Я не спускал вниз, но этот алгоритм, по крайней мере, O (n^2), когда он должен быть намного проще. – dreamlax

+1

Да, наверное, не самый лучший способ. – jpswain

2

Учитывая два предположения: что порядок не имеет значения (или может быть восстановлен - например, если массивы сортируются в настоящее время) * и что ни один элемент не появляется более чем один раз в любом массив (хотя вы можете использовать подсчитанный набор для этого), набор может быть хорошим выбором.

XOR (строго симметричная разность) двух множеств является объединением минус пересечение:

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

[unioned minusSet:intersection]; 

* Если порядок важен, вы можете использовать NSOrderedSet.

7

Как насчет использования предикатов?

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", needs]; 
NSArray *wants_needs = [wants filteredArrayUsingPredicate:predicate]; 
Смежные вопросы