views:

64

answers:

3

Is there a way to have multiple loop variables in a for statement? Here would be a hypothetical representation of what I'm talking about:

for (NSString *foo in bar; NSString *bob in example) {}

If not what is a good way to accomplish this?

Thanks,

Kolin

+1  A: 

No, not using the fast enumeration syntax anyway.

Joshua Weinberg
Is there anything that I can do that has comparable results?
Kolin Krewinkel
Depends more on what you're specifically trying to accomplish
Joshua Weinberg
+3  A: 

Joshua is right that there's no way to do it with fast enumeration syntax but there's a couple of ways (at least) you can achieve something similar. Which approach you prefer depends on whether you're trying avoid the overhead of running the loop twice or whether you're trying to avoid the visual clutter of having two separate loops in your code.

Assuming you have two collections of NSStrings (they don't need to be NSArrays btw)

    NSArray* foo = [NSArray arrayWithObjects:@"bar1", @"bar2", @"bar3", @"bar4", @"bar5", nil];
NSArray* example = [NSArray arrayWithObjects:@"example1", @"example2", nil];

If you're looking to iterate over all the elements of both collections you can do the following:

    NSEnumerator* fooEnumerator = [foo objectEnumerator];
NSEnumerator* exampleEnumerator = [example objectEnumerator];

NSString *bar, *bob;

while ((bar = [fooEnumerator nextObject]) || (bob = [exampleEnumerator nextObject])) {
    if (bar) {
        NSLog(@"%@", bar);
    }
    if (bob) {
        NSLog(@"%@", bob);
    }
}

this will iterate over all of bar's elements first and then over all of example's elements (i.e. it will output: bar1, bar2, bar3, bar4, bar5, example1, example2).

if you want to minimize the number of iterations of the loop and don't necessarily need to run through all the elements of both collections you can try replacing the while loop above with:

while ((bar = [fooEnumerator nextObject]) && (bob = [exampleEnumerator nextObject])) {
    NSLog(@"%@", bar);
    NSLog(@"%@", bob);
}

This will loop through both collections simultaneously but will stop as soon as one of the collections runs out of elements (i.e. it will output: bar1, example1, bar2, example2)

Just as a note though, it's pretty rare that loops have a meaningful impact on performance so if this is all to avoid the runtime cost of two loops you're likely better served by other optimizations.

Mattia
Thanks! This works perfectly.
Kolin Krewinkel
+1  A: 

Assuming blocks, an alternative:

NSAssert([foo count] == [bar count]);
[foo enumerateUsingBlock: ^(id fooObj, NSUInteger index, BOOL *stopFlag) {
    id barObj = [bar objectAtIndex: index];
    ... do stuff here ...
}];
bbum
Thanks..will try this when the minimum os is iOS4.
Kolin Krewinkel