Skip to content

Instantly share code, notes, and snippets.

@rcdilorenzo
Created August 26, 2016 15:25
Show Gist options
  • Select an option

  • Save rcdilorenzo/8f5591bf98ce37a342236eec9a3b6cc5 to your computer and use it in GitHub Desktop.

Select an option

Save rcdilorenzo/8f5591bf98ce37a342236eec9a3b6cc5 to your computer and use it in GitHub Desktop.
A class to diff between two types of arrays (take a look at the test to see how it works)
#import <Foundation/Foundation.h>
typedef BOOL(^NSArrayDiffMatch)(id _Nonnull original, id _Nonnull comparedTo);
@interface NSArrayDiff : NSObject
+ (instancetype _Nonnull)newWithOriginal:(NSArray * _Nonnull)original
diffedAgainst:(NSArray * _Nonnull)compareTo
match:(NSArrayDiffMatch _Nonnull)match;
@property (nonatomic, strong, readonly) NSIndexSet * _Nonnull removedIndexes;
@property (nonatomic, strong, readonly) NSArray * _Nonnull removedObjects;
@property (nonatomic, strong, readonly) NSIndexSet * _Nonnull addedIndexes;
@property (nonatomic, strong, readonly) NSArray * _Nonnull addedObjects;
@end
#import "NSArrayDiff.h"
@interface NSArrayDiff()
@property (nonatomic, strong) NSArrayDiffMatch match;
@property (nonatomic, strong) NSArray *original;
@property (nonatomic, strong) NSArray *comparedTo;
@property (nonatomic, strong) NSMutableIndexSet *removedMutableIndexes;
@property (nonatomic, strong) NSMutableIndexSet *addedMutableIndexes;
@end
@implementation NSArrayDiff
+ (instancetype)newWithOriginal:(NSArray *)original diffedAgainst:(NSArray *)compareTo match:(NSArrayDiffMatch)match {
NSArrayDiff *diff = [self new];
diff.original = original;
diff.comparedTo = compareTo;
diff.match = match;
[diff compare];
return diff;
}
/**
* Compare is an speed-optimized function to diff
* arrays since it will be often used. Its time
* complexity is O(n^2) and uses the fast enumeration
* for..in loop.
*/
- (void)compare {
NSUInteger index = 0;
for (id original in self.original) {
BOOL found = false;
for (id comparedTo in self.comparedTo) {
if (self.match(original, comparedTo)) {
found = true;
break;
}
}
if (!found) {
[self.removedMutableIndexes addIndex:index];
}
index++;
}
index = 0;
for (id comparedTo in self.comparedTo) {
BOOL found = false;
for (id original in self.original) {
if (self.match(original, comparedTo)) {
found = true;
break;
}
}
if (!found) {
[self.addedMutableIndexes addIndex:index];
}
index++;
}
}
- (NSIndexSet *)addedMutableIndexes {
if (!_addedMutableIndexes) {
_addedMutableIndexes = [NSMutableIndexSet new];
}
return _addedMutableIndexes;
}
- (NSIndexSet *)removedMutableIndexes {
if (!_removedMutableIndexes) {
_removedMutableIndexes = [NSMutableIndexSet new];
}
return _removedMutableIndexes;
}
- (NSIndexSet *)addedIndexes {
return [self.addedMutableIndexes copy];
}
- (NSIndexSet *)removedIndexes {
return [self.removedMutableIndexes copy];
}
- (NSArray *)addedObjects {
return [self.comparedTo objectsAtIndexes:self.addedMutableIndexes];
}
- (NSArray *)removedObjects {
return [self.original objectsAtIndexes:self.removedMutableIndexes];
}
@end
#import <XCTest/XCTest.h>
#define EXP_SHORTHAND
#import "Expecta.h"
#import "NSArrayDiff.h"
@interface NSArrayDiffTests : XCTestCase
@end
@implementation NSArrayDiffTests
- (void)testDiffing {
NSArray *firstNames = @[@"Fred", @"Adam", @"Sam", @"Craig"];
NSArray *fullNames = @[@"Fred Smith", @"Adam Helbing", @"Nicholas Pizaro", @"Craig Elmot"];
__block NSArrayDiff *diff;
[self measureBlock:^{
diff = [NSArrayDiff newWithOriginal:firstNames diffedAgainst:fullNames match:^BOOL(NSString *first, NSString *full) {
return [[[full componentsSeparatedByString:@" "] firstObject] isEqualToString:first];
}];
}];
expect(diff.addedObjects).to.equal(@[@"Nicholas Pizaro"]);
expect(diff.removedObjects).to.equal(@[@"Sam"]);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment