14

I have an NSArray, and I want to split it into two equal pieces (if odd "count" then add to the latter new array) - I want to split it "down the middle" so to speak.

The following code does exactly what I want, but is there a better way?:

// NOTE: `NSArray testableArray` is an NSArray of objects from a class defined elsewhere;
NSMutableArray *leftArray = [[NSMutableArray alloc] init];  
NSMutableArray *rightArray = [[NSMutableArray alloc] init];

for (int i=0; i < [testableArray count]; i=i+1) {
if (i < [testableArray count]/2) {
        [leftArray addObject:[testableArray objectAtIndex:i]];
    }
    else {
        [rightArray addObject:[testableArray objectAtIndex:i]];
    }
}

Once leftArray and rightArray are made, I will not change them, so they do not need to be "mutable". I think there may be a way to accomplish the above code with the ObjectsAtIndexes method or some fast enumeration method?, but I cannot get the following code to work (or other variations):

NSArray *leftArray = [[NSArray alloc] initWithObjects:[testableArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(????, ????)]]];
NSArray *rightArray = [[NSArray alloc] initWithObjects:[testableArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(????, ????)]]];

Does anyone know if I am going in the right direction with this or point me in the correct direction?

Thanks!

pavium
  • 14,808
  • 4
  • 33
  • 50
J. Dave
  • 335
  • 1
  • 4
  • 10

3 Answers3

45

You also have the option of using -subarrayWithRange: detailed in the NSArray documentation:

NSArray *firstHalfOfArray;
NSArray *secondHalfOfArray;
NSRange someRange;

someRange.location = 0;
someRange.length = [wholeArray count] / 2;

firstHalfOfArray = [wholeArray subarrayWithRange:someRange];

someRange.location = someRange.length;
someRange.length = [wholeArray count] - someRange.length;

secondHalfOfArray = [wholeArray subarrayWithRange:someRange];

This method returns new, autorelease-d arrays.

Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • Alex, thanks for your ultra-quick response(s)! Your second solution is much better. I think I got too hung up implementing NSRange, which you also laid out very clearly in the above example! – J. Dave Nov 20 '09 at 03:30
  • 1
    there is a bug here. There is no need to +1. Example: an array of 6 elements. the first NSRange should be {0, 3} the second NSRange should be {3, 3}. In your case you'll get an exception because the second range would be out of bounds {4, 3}. – Stas Zhukovskiy Oct 09 '13 at 19:03
  • You can do this with less lines using NSMakeRange, for example: NSArray* firstHalf = [wholeArray subarrayWithRange:NSMakeRange(0, [wholeArray count]/2)]; NSArray* secondHalf = [wholeArray subarrayWithRange:NSMakeRange([wholeArray count]/2, [wholeArray count] - [wholeArray count]/2)]; – DFectuoso Aug 31 '14 at 05:28
2

Have you tried adding nil to the end of the -initWithObjects: method?

NSArray *leftArray = [[NSArray alloc] initWithObjects:[testableArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(????, ????)]], nil];
NSArray *rightArray = [[NSArray alloc] initWithObjects:[testableArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(????, ????)]], nil];
Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • Thanks, such a quick response! I tried the above code, but I get an error related to my class, so I think I am specifying NSRange incorrectly. – J. Dave Nov 20 '09 at 03:31
0

If you want an extra object on first array (in case total items are odd), use following code modified from Alex's answer:

NSArray *arrayTotal = [NSArray arrayWithObjects:@"A", nil];
//NSArray *arrayTotal = [NSArray arrayWithObjects:@"A", @"B", nil];
//NSArray *arrayTotal = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];
//NSArray *arrayTotal = [NSArray arrayWithObjects:@"A", @"B", @"C", @"D", nil];
//NSArray *arrayTotal = [NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", nil];

NSArray *arrLeft;
NSArray *arrRight;

NSRange range;
range.location = 0;
range.length = ([arrayTotal count] % 2) ? ([arrayTotal count] / 2) + 1 : ([arrayTotal count] / 2);

arrLeft = [arrayTotal subarrayWithRange:range];

range.location = range.length;
range.length = [arrayTotal count] - range.length;

arrRight = [arrayTotal subarrayWithRange:range];

NSLog(@"Objects: %lu", (unsigned long)[arrLeft count]);
NSLog(@"%@", [arrLeft description]);

NSLog(@"Objects: %lu", (unsigned long)[arrRight count]);
NSLog(@"%@", [arrRight description]);
NSPratik
  • 4,714
  • 7
  • 51
  • 81