7

I'm trying to use NSRange to hold a range of years, such as

NSRange years = NSMakeRange(2011, 5);

I know NSRange is used mostly for filtering, however I want to loop over the elements in the range. Is that possible without converting the NSRange into a NSArray?

jscs
  • 62,161
  • 12
  • 145
  • 186
aporat
  • 5,832
  • 5
  • 27
  • 54

4 Answers4

8

It kind of sounds like you're expecting NSRange to be like a Python range object. It's not; NSRange is simply a struct

typedef struct _NSRange {
       NSUInteger location;
       NSUInteger length;
} NSRange;

not an object. Once you've created one, you can use its members in a plain old for loop:

NSUInteger year;
for(year = years.location; year < NSMaxRange(years); year++ ){
    // Do your thing.
}

(Still working on the assumption that you're thinking about Python.) There's syntax in ObjC called fast enumeration for iterating over the contents of an NSArray that is pleasantly similar to a Python for loop, but since literal and primitive numbers can't be put into an NSArray, you can't go directly from an NSRange to a Cocoa array.

A category could make that easier, though:

@implementation NSArray (WSSRangeArray)

+ (id)WSSArrayWithNumbersInRange:(NSRange)range
{
    NSMutableArray * arr = [NSMutableArray array];
    NSUInteger i;
    for( i = range.location; i < NSMaxRange(range); i++ ){
        [arr addObject:[NSNumber numberWithUnsignedInteger:i]];
    }

    return arr;
}

Then you can create an array and use fast enumeration:

NSArray * years = [NSArray WSSArrayWithNumbersInRange:NSMakeRange(2011, 5)];
for( NSNumber * yearNum in years ){
    NSUInteger year = [yearNum unsignedIntegerValue];
    // and so on...
}
jscs
  • 62,161
  • 12
  • 145
  • 186
  • thanks, too bad there's no support for fast enumeration for NSRange. could save me some time and code lines – aporat Nov 30 '11 at 04:43
  • @manroe: I appreciate your correction of my coding error, but the big "EDIT:" block was inappropriate; it could have been a comment, the edit summary, or really just left out altogether. – jscs Sep 30 '15 at 19:37
6

Remember that a NSRange is a structure holding two integers, representing the start and length of the range. You can easily loop over all of the contained integers using a for loop.

NSRange years = NSMakeRange(2011, 5);
NSUInteger year;
for(year = years.location; year < years.location + years.length; ++year) {
    // Use the year variable here
}
Mason
  • 4,573
  • 3
  • 22
  • 23
ughoavgfhw
  • 39,083
  • 6
  • 98
  • 121
3

This is a bit of an old question, but an alternative to using an NSArray would be to create an NSIndexSet with the desired range (using indexWithIndexesInRange: or initWithIndexesInRange:) and then using block enumeration as in https://stackoverflow.com/a/4209289/138772. (Seemed relevant as I was just checking on this myself.)

Community
  • 1
  • 1
JAB
  • 19,150
  • 4
  • 64
  • 78
0

My alternate solution for this, was to define a macro just to make shorthand quicker.

#define NSRangeEnumerate(i, range)    for(i = range.location; i < NSMaxRange(range); ++i)

To call it you do:

NSArray *array = @[]; // must contain at least the following range...
NSRange range = NSMakeRange(2011, 5);
NSUInteger i;
NSRangeEnumerate(i, range) {
    id item = array[i];
    // do your thing
}

personally I am still trying to figure out how I can write the macro so I can just call it like:

NSRangeEnumerate(NSUInteger i, range) {

}

which is not supported just yet... hope that helps or makes typing your program quicker

NoodleOfDeath
  • 13,338
  • 21
  • 69
  • 100