Looping using NSRange
Asked Answered
D

4

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?

Desimone answered 30/11, 2011 at 4:2 Comment(0)
Q
9

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...
}
Quieten answered 30/11, 2011 at 4:10 Comment(2)
thanks, too bad there's no support for fast enumeration for NSRange. could save me some time and code linesDesimone
@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.Quieten
C
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
}
Changeover answered 30/11, 2011 at 4:9 Comment(0)
A
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://mcmap.net/q/349337/-fast-enumeration-on-an-nsindexset. (Seemed relevant as I was just checking on this myself.)

Amphictyony answered 1/7, 2013 at 14:30 Comment(0)
C
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

Clever answered 25/8, 2014 at 13:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.