I've been trying to sort an NSArray of NSDictionaries using a comparator, but I cannot seem to get the output I desire.
The output I'm trying to achieve is that A-Z usernames should come first in the sorted array, then usernames that start with a digit should come second in the sorted array, and lastly usernames that start with an underscore should be last in the sorted array. Any help is truly appreciated!
EDIT: It should be sorted so it looks consistent through the whole NSArray so that: _Anna comes before _Bob and _11Bob comes before _12Cary but after _09Bob
Example of desired output I'm looking for:
(
{
username = abcd;
},
{
username = Anna;
},
{
username = 01Bob;
},
{
username = 02Tob;
},
{
username = 03ZED;
},
{
username = 04_Hob;
},
{
username = 04_sob;
},
{
username = "_anna";
},
{
username = "_bob";
},
{
username = "_boc";
},
{
username = "_bocd12";
},
{
username = "_bocd13";
}
{
username = _01Bob;
},
{
username = _02Tob;
},
)
I hope that makes sense now.
Sample NSDictionary with an NSArray of NSDictionaries:
NSDictionary *dictionary = @{@"users":@[@{@"username":@"191anna"},@{@"username":@"_091bob"},@{@"username":@"Bob"},@{@"username":@"charlie"}]};
I'm trying by using this comparator:
NSArray *array = [[dictionary objectForKey:@"users"] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSString *f1 = [obj1 objectForKey:@"username"];
NSString *f2 = [obj2 objectForKey:@"username"];
NSString *s1 = [[obj1 objectForKey:@"username"]substringFromIndex:1];
NSString *s2 = [[obj2 objectForKey:@"username"]substringFromIndex:1];
if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location == [s2 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location)
{
return [f1 localizedCaseInsensitiveCompare:f2];
}
else if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != [s2 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location)
{
return [f1 localizedCaseInsensitiveCompare:f2];
if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location == NSNotFound)
{
return NSOrderedDescending;
}
}
return NSOrderedAscending;
}];
But it gives me the following (not the way I want) sorted NSArray:
(
{
username = "_091bob";
},
{
username = 191anna;
},
{
username = Bob;
},
{
username = charlie;
}
)
You can optimize this further, but your sort logic would be like below.
Here's what I came up with. It's a touch long because it requires quite a bit of logic. It can likely be optimized further:
My Set Up:
And The Sort:
Will log as: