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
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];
}
}];
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];
}];
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]];
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]];
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"datetime"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSArray *sortedArray = [myArrayNonsort sortedArrayUsingDescriptors:sortDescriptors];
sortedArray = [anArray sortedArrayUsingSelector:
@selector(localizedCaseInsensitiveCompare:)];
input:anArray
output:sortedArray
refer the docs