2

I get an array of strings with the following strings, there is a certain patern to the strings

str1 str51 str3 str4 str10 str39 str31 str191

Every string starts with 'str' and has a number appended onto the end of it.

Is there a neath way to sort the array so it lists the strings in order of value

str1 str3 str4 str10 str31 str39 str51 str191

I can see a way to do it by writing some recursive function that will

NSString * firstString = [[strArray objectAtIndex:i].substringFromIndex:3];
NSString * secondString = [[strArray objectAtIndex:i+1].substringFromIndex:3];

if ([firstString intValue] < [secondString intValue])
{
    //do nothing they order is correct
}
else
{
    //swap the order of the 2 strings in the array
}

But thats very rudimentary code, Is there some mechanism in Objective-C or a nice code trick to handle this sorting better?

Many Thanks, -Code

6 Answers6

5

If they all start with the same prefix, I believe that the default sort will handle them appropriately. By this, I mean:

[someArray sortUsingSelector:@selector(compare:)];

If, for some reason, this isn't working, then you can use a block. Try this:

NSArray *sortedArray = [someArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
{
    //Default compare, to protect against cast
    if (![a isKindOfClass:[NSString class]] || ![b isKindOfClass:[NSString class]]) {
        return ([a compare:b]);
    }
    else {
        NSString *aString = (NSString*) a;
        NSString *bString = (NSString*) b;
        int aInt = [[a.substringFromIndex:3] intValue];
        int bInt = [[b.substringFromIndex:3] intValue];
        return [aInt < bInt];
    }
}];
Charles Marsh
  • 1,877
  • 16
  • 21
  • The default sort is lexicographical, so unfortunately you do have to resort to mild trickery in this case. – warrenm Jul 27 '12 at 09:50
2

You could sort it like this

NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    NSString * str1 = [(NSString *)obj1 substringFromIndex:3];
    NSString * str2 = [(NSString *)obj2 substringFromIndex:3];
    return [str1 compare:str2 options:NSNumericSearch];
}];
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • It doesn't make a lot of sense to cast a Boolean to an `NSComparisonResult`. You could do this instead, though: `return ([str1 intValue] - [str2 intValue]);` – warrenm Jul 27 '12 at 09:42
  • I agree that it's best to do so, but all of the Foundation sorting algorithms are forgiving in that regard. – warrenm Jul 27 '12 at 09:47
  • @warrenm I changed it to doing a numeric search instead. That reads more clearly to me. – David Rönnqvist Jul 27 '12 at 09:48
0

You can define a comparator function with whatever behavior you want. The one below will emulate the behavior of Finder in Mac OS, ignoring case and respecting numbers occurring at the end of strings. The order will be dependent on the provided locale, though, so if you want the results to be absolutely consistent, you should pick a locale and hard-code it.

int finderSortWithLocale(id string1, id string2, void *locale)
{
    static NSStringCompareOptions comparisonOptions =
        NSCaseInsensitiveSearch | NSNumericSearch |
        NSWidthInsensitiveSearch | NSForcedOrderingSearch;

    NSRange string1Range = NSMakeRange(0, [string1 length]);

    return [string1 compare:string2
                    options:comparisonOptions
                    range:string1Range
                    locale:(__bridge NSLocale *)locale];
}

You should definitely read the documentation on each of those options to ensure it does what you're looking for.

To use such a comparator to efficiently sort a string array, use the sortedArrayUsingFunction:context: method:

NSArray *sortedArray = [stringsArray sortedArrayUsingFunction:finderSortWithLocale context:(__bridge void *)[NSLocale currentLocale]];
warrenm
  • 31,094
  • 6
  • 92
  • 116
0

Create a NSSortDescriptor and sort the array on the key: "description". Like This:

NSMutableArray *array = [NSMutableArray arrayWithCapacity:0]; //Your Array of NSStrings
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES];
array = [array sortedArrayUsingDescriptors:@[descriptor]];
0
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"datetime"
                                                             ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSArray *sortedArray = [myArrayNonsort sortedArrayUsingDescriptors:sortDescriptors];
ArNo
  • 2,278
  • 1
  • 22
  • 19
-1

sortedArray = [anArray sortedArrayUsingSelector: @selector(localizedCaseInsensitiveCompare:)];

input:anArray output:sortedArray

refer the docs

Lithu T.V
  • 19,955
  • 12
  • 56
  • 101