1

Given an NSRange, such as:

NSRange range = NSMakeRange(1, 22);

What's the best way to convert it to a comma-separated string of its values?

@"1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22"

The best I could come up with was to iterate over the range and insert its values into an NSArray, and then call -componentsJoinedByString: on the array. But that seems pretty wasteful, not to mention inelegant. Is there no better way?

theory
  • 9,178
  • 10
  • 59
  • 129
  • 1
    Not that I'm aware of. This is not python. ;) – dasdom May 12 '14 at 18:55
  • @dasdom So you know where I'm coming from, eh? I'm used to it being easy: `perl -E 'say join ",", 1..22'` – theory May 12 '14 at 18:57
  • `NSMutableString *string = [[NSMutableString alloc] init];for (int i = range.location; i < range.length; i ++){[string appendFormat:"%d,",i]};[string deleteCharactersInRange:NSMakeRange(string.length-1,1)];` ? That's the kind of thing your looking for? – Larme May 12 '14 at 18:59
  • @Larme Yeah, as in J2thC's answer. So ugly, though. – theory May 12 '14 at 19:01
  • Well, usually that's not the role of a `NSRange`, I only used it in NSString actually, and we don't often use that (well, I didn't see a use)... If there is some logic, why not create it on the fly? You want element 3? `[NSString stringWithFormat:@"%d", 3+offsetStart]`. – Larme May 12 '14 at 19:05
  • 2
    Similar/related: [Looping using NSRange](http://stackoverflow.com/q/8320987) (note wistful mention of Python there too!) – jscs May 12 '14 at 21:05

3 Answers3

2
NSMutableString *string=[@"" mutableCopy];
for (int i = range.location; i<range.length-1; i++){
   [string appendFormat:@"%d,", i];
}
[string appendString@"%d", range.length-1];

If you want to hide the code, you can turn it into a function that would take the range and turn it into a string, that way this is hidden from your code. Or maybe turn it into a NSString class method, something like

[NSString stringWithRangeValues:range];

That would be like:

+ (NSString *)stringWithRangeValues:(NSRange)range{
        NSMutableString *string=[@"" mutableCopy];
        for (int i = range.location; i<range.lenght-1; i++){
           [string appendFormat:@"%d,", i];
        }
        [string appendString@"%d", range.length-1];
        return [NSString stringWithString:string];

}

jscs
  • 63,694
  • 13
  • 151
  • 195
J2theC
  • 4,412
  • 1
  • 12
  • 14
2

My version using an array:

NSMutableArray *vals = [NSMutableArray arrayWithCapacity:range.length];
for (NSUInteger i = range.location; i < range.length; i++){
    [vals addObject:@(i)];
}
NSString *string = [vals componentsJoinedByString:@","];
theory
  • 9,178
  • 10
  • 59
  • 129
2

You can use NSIndexSet with indexSetWithIndexesInRange: to generate a list of values, and then iterate through them with enumerateIndexesUsingBlock:. E.g.

NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
NSMutableArray *indices = [NSMutableArray array];
[indexSet enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop) {
    [indices addObject:@(i)];
}];
NSString *string = [indices componentsJoinedByString:","];
Dan Loewenherz
  • 10,879
  • 7
  • 50
  • 81
  • 1
    Maybe I should have asked for increasingly complex ways to solve this problem. ;-P – theory May 12 '14 at 20:03
  • Hah. It was all I could think of :) I thought there might have been a way to convert an NSIndexSet to an NSArray populated with the indices of the elements, but alas, no dice. NSIndexSet is basically the higher-level version of an NSRange so my answer doesn't quite have too much of a benefit, unless you want to stay away from using NSRange directly. – Dan Loewenherz May 12 '14 at 21:06