16

I have two NSArrays A and B that share some common elements, e.g.

A: 1,2,3,4,5 
B: 4,5,6,7

I would like to create a new NSArray consisting of the contents common between the two NSArrays joined with the contents of the second NSArray while maintaining the order of the elements and removing duplicates. That is, I would like (A ∩ B) ∪ B.

The operation on the previous NSArrays would yield:

A ∩ B: 4,5
(A ∩ B) ∪ B: 4,5,6,7

How do I accomplish this in Objective-C?

Mat Kelly
  • 2,327
  • 7
  • 29
  • 51
  • 1
    suppose you wanted something more reasonable than this, but (A ∩ B) ∪ B really doesn't make much sense: it's just B. – galactica Sep 26 '18 at 00:11

5 Answers5

25

Convert the NSArrays to NSSets, the standard set operations are available.

NSArray *a = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", @"5", nil];
NSArray *b = [NSArray arrayWithObjects:@"4", @"5", @"6", @"7", nil];

NSMutableSet *setA = [NSMutableSet setWithArray:a];
NSSet *setB = [NSSet setWithArray:b];
[setA intersectSet:setB];
NSLog(@"c: %@", [setA allObjects]);

NSLog output: c: (4, 5)

[setA unionSet:setB];
NSLog(@"d: %@", [setA allObjects]);

NSLog output: d: (6, 4, 7, 5)

Zack Brown
  • 5,990
  • 2
  • 41
  • 54
zaph
  • 111,848
  • 21
  • 189
  • 228
15

As others have suggested, you can easily do this with NSSet. However, this will not preserve ordering.

If you want to preserve ordering and you can target OS X 10.7+, then you can use the new NSOrderedSet (and mutable subclass) to do the same thing.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Most seemed to have missed the important aspect of preserving order, which rules out NSSet. My target is iOS 4.3, which does not appear to have the NSOrderedSet library. Any other ideas? – Mat Kelly Oct 07 '11 at 14:56
  • @Mat use the `NSSet` approach, but then manually extract the elements from `B` that are in the final set. You'll have to preserve order yourself. – Dave DeLong Oct 07 '11 at 14:59
  • thanks again for the response. I think there is a better way of doing this than resorting to NSSet, which doesn't preserve order. I will probably have to write my own functions/library to do this but wanted to know if the operations were already in-place so I wouldn't be re-inventing the wheel. If so, I will likely post it here in case others run into this sort of issue. – Mat Kelly Oct 07 '11 at 16:43
  • 2
    @Mat I'd also like to point out that "(A intersect B) union B" will *always* result in "B". – Dave DeLong Oct 07 '11 at 18:26
  • Dave, you are correct and I realized this upon implementation. What I would like is that which is unique to B. I believe this can be conveyed with NOT(A union B) intersect NOT(B). Does that represent what I would like correctly? Thanks for the correction! – Mat Kelly Oct 07 '11 at 20:18
  • @Mat that would be just `B - A`. – Dave DeLong Oct 07 '11 at 20:23
  • Dave, I understand that but what would be the equivalent using intersection and union notation? – Mat Kelly Oct 08 '11 at 14:58
  • @Mat I don't believe that's possible. Why can't you use minus? – Dave DeLong Oct 08 '11 at 16:08
6

By using NSSet, as others have pointed out. For

NSArray * a = [NSArray arrayWithObjects: ... ];
NSArray * b = [NSArray arratWithObjects: ... ];
NSMutableSet * set = [NSMutableSet setWithArray:a];
[set intersectSet:[NSSet setWithArray:b];
[set unionSet:[NSSet setWithArray:b];

This takes care of dupes but won't preserve order. You'd take the results in "set" and sort them back into an array. There's no native collection functionality that will do it all-- if you prefer to keep the order and worry about dupes separately, use NSMutableArray's -removeObjectsInArray: method, etc.

Ben Zotto
  • 70,108
  • 23
  • 141
  • 204
2

(A ∩ B) ∪ B will always give you B, so this is a pretty bizarre thing to want to calculate. It's like saying "Give me the set of all cars that are colored green, combined with the set of all cars". That's going to give you the set of all cars.

Kaitain
  • 911
  • 12
  • 19
0

There is an NSSet class you can use to perform these operations.

Joshua Weinberg
  • 28,598
  • 2
  • 97
  • 90