前幾天被問到如何取得兩個 array 的差集合,
舉例來說,有 array A, B 各為下
a = [1, 3, 4]
b = [2, 3, 4]
就會取得一個 diff array
diff = [1, 2]
在 NSArray
也沒有直接就可以取得差集的 API ,只有 NSMutableArray
的 removeObjectsInArray
,但是這又只能對一個 array 移除和另外一個 array 有重複的物件。
這時候的解法就會是
- 先取得各自的差集
- 再把差集合併起來
NSArray *numbersA = @[@1, @3, @4];
NSArray *numbersB = @[@2, @3, @4];
NSMutableArray *diff = [NSMutableArray array];
NSMutableArray *diffA = [numbersA mutableCopy];
[diffA removeObjectsInArray:numbersB];
NSMutableArray *diffB = [numbersB mutableCopy];
[diffB removeObjectsInArray:numbersA];
[diff addObjectsFromArray:diffA];
[diff addObjectsFromArray:diffB];
這時候的 diff
就會是兩者個別差集後合併起來的陣列
用 NSMutableSet 做集合運算
接著找了找,找到一篇文章,用 NSMutableSet 的 intersect 和 minus 兩個 methods 可以來做交集合和集合相減。
運算邏輯
於是這個運算會分成三個步驟
- 將兩個 arrays 合併成一個 NSMutableSet
- 找出兩個 arrays 中有重複的元素
- 將合併的 set 移除重複的元素
- 轉換回 NSArray
解法
一樣先創建兩個 arrays
NSArray *numbersA = @[@1, @3, @4];
NSArray *numbersB = @[@2, @3, @4];
接著把邏輯實作出來:
// 合併兩個 arrays
NSMutableSet *numbersSet = [NSMutableSet setWithArray:numbersA];
[numbersSet addObjectsFromArray:numbersB];
// 找出兩者皆有的元素
NSMutableSet *duplicatedSet = [NSMutableSet setWithArray:numbersA];
[duplicatedSet intersectSet:[NSSet setWithArray:numbersB]];
// 減掉重複的元素
[numbersSet minusSet:duplicatedSet];
// 轉換回 array
NSArray *diff = [numbersSet allObjects];
排序
NSSet
本身並沒有將元素排序,將 array 轉換成 set 之後,原本的順序就會亂掉。
因此,上一節所得的結果,可能會是 [1,2] ,也有可能是 [2,1] 。
如果想要排序,就可以改用 NSMutableOrderedSet
和相關的 methods :
NSMutableOrderedSet *numbersSet = [NSMutableOrderedSet orderedSetWithArray:numbersA];
[numbersSet addObjectsFromArray:numbersB];
NSMutableOrderedSet *duplicatedSet = [NSMutableOrderedSet orderedSetWithArray:numbersA];
[duplicatedSet intersectOrderedSet:[NSOrderedSet orderedSetWithArray:numbersB]];
[numbersSet minusOrderedSet:duplicatedSet];
感想
現在雖然知道解法,不過還不太清楚,單純使用 array 運算和使用 NSSet 做集合運算的優缺點在哪裡。
目前看 NSSet 的方式雖然要先轉換型態,但是覺得這個邏輯寫起來還比前者漂亮、容易理解。
【更新】
單純使用 array 的方法沒有繞一圈跑去用 NSSet 處理後再轉回來成 array ,看起來也比較直接,說不定我會比較喜歡這個