How to sort an array controller alphabetically with numbers last in objective-c?

I have an NSArrayController , and I would like to sort the contents so that something with English alphabets is sorted first, and then all with numbers and non-English characters are sorted last.

For example: A, B, C ... Z, 1, 2, 3 ... 9, 구, 결, ...

Currently, I only know how to sort the elements in alphabetical order. Suggestions?

 NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; [dataController setSortDescriptors: [NSArray arrayWithObject: sort]]; 
+4
source share
5 answers

You can use sortedArrayUsingComparator to customize the sorting algorithm to suit your needs. For example, you can assign characters with the following lines:

 NSArray *assorted = [@"1 2 3 9 ; : 구 , 결 ABCZ ! á" componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *sorted = [assorted sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { /* NSOrderedAscending, NSOrderedSame, NSOrderedDescending */ BOOL isPunct1 = [[NSCharacterSet punctuationCharacterSet] characterIsMember:[(NSString*)obj1 characterAtIndex:0]]; BOOL isPunct2 = [[NSCharacterSet punctuationCharacterSet] characterIsMember:[(NSString*)obj2 characterAtIndex:0]]; if (isPunct1 && !isPunct2) { return NSOrderedAscending; } else if (!isPunct1 && isPunct2) { return NSOrderedDescending; } return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch]; }]; 

To put English characters before non-English, it would be enough to use NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch as parameters, without requiring a fantastic algorithm.

If you need to support iOS without blocks, try sortedArrayUsingSelector .

+10
source

Another solution by testing if the string is encoded in Latin:

  • for both strings, if the first character is a Latin (aka English) character
  • if they are both, check if both begin with a letter or a number. In both cases, leave it compare:
  • else, if you start with a number and a letter with the letter return NSOrderingAscending , if the first with the letter is the first, otherwise NSOrderingDescending

  • If both strings are not Latin let compare: solve again

  • if it is Latin and one is not, return NSOrderingAscending , if Latin is the first, otherwise NSOrderingDescending

code

 NSArray *array = [NSArray arrayWithObjects:@"peach",@"apple",@"7",@"banana",@"ananas",@"5", @"papaya",@"4",@"구",@"결",@"1" ,nil]; array = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSString *s1 = [obj1 substringToIndex:1]; NSString *s2 = [obj2 substringToIndex:1]; BOOL b1 = [s1 canBeConvertedToEncoding:NSISOLatin1StringEncoding]; BOOL b2 = [s2 canBeConvertedToEncoding:NSISOLatin1StringEncoding]; if ((b1 == b2) && b1) {//both number or latin char NSRange r1 = [s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]]; NSRange r2 = [s2 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]]; if (r1.location == r2.location ) { // either both start with a number or both with a letter return [obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch]; } else { // one starts wit a letter, the other with a number if ([s1 rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location == NSNotFound) { return NSOrderedAscending; } return NSOrderedDescending; } } else if((b1 == b2) && !b1){ // neither latin char return [obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch]; } else { //one is latin char, other not if (b1) return NSOrderedAscending; return NSOrderedDescending; } }]; for (NSString *s in array) NSLog(@"%@", s); 

result

 ananas apple banana papaya peach 1 4 5 7 구 결 
+4
source

I don’t think you can do this sorting without defining your own comparison function.

For this purpose you can use sortedArrayUsingFunction :

 [array sortedArrayUsingFunction:f context:userContext]; 

where f is defined as:

 NSInteger f(id num1, id num2, void *context) { int v1 = [num1 intValue]; int v2 = [num2 intValue]; if (...) return NSOrderedAscending; else if (...) return NSOrderedDescending; else return NSOrderedSame; } 

If you prefer not to create a function for this, you can use the block version of the method, sortedArrayUsingComparator :

 [array sortedArrayUsingComparator: ^(id obj1, id obj2) { return NSOrderedSame; }]; 
+3
source

A comparator based sort descriptor should do the trick (note: not verified).

 NSComparator cmp = ^(id str1, id str2) { // Make your sorting if ( /* str1 before str2 */ ) return NSOrderedAscending else if ( /* str2 after str1 */ ) return NSOrderedDescending else return NSOrderedSame }; NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey: sortKey ascending: YES comparator: cmp]; NSArrayController *ac = // ... [ac setSortDescriptor: sd]; 

Of course, you must define your own sort order algorithm, but this example should show how to use the sort descriptor for an array controller.

+1
source

There is no need to answer the question correctly: NSNumericSearch

 NSArray *assorted = [@"1 2 3 9 ; : 구 , 결 ABCZ ! á" componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *sorted = [assorted sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { /* NSOrderedAscending, NSOrderedSame, NSOrderedDescending */ BOOL isPunct1 = [[NSCharacterSet punctuationCharacterSet] characterIsMember:[(NSString*)obj1 characterAtIndex:0]]; BOOL isPunct2 = [[NSCharacterSet punctuationCharacterSet] characterIsMember:[(NSString*)obj2 characterAtIndex:0]]; if (isPunct1 && !isPunct2) { return NSOrderedAscending; } else if (!isPunct1 && isPunct2) { return NSOrderedDescending; } return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch|NSNumericSearch]|; }]; 
0
source

Source: https://habr.com/ru/post/1382697/


All Articles