Как отсортировать контроллер массива в алфавитном порядке по номерам, последним в target-c? - PullRequest
4 голосов
/ 23 ноября 2011

У меня есть NSArrayController, и я хотел бы отсортировать содержимое так, чтобы сначала сортировались все, что с английскими алфавитами, а затем все, что с цифрами и не английскими символами, сортировалось последним.

Например: A, B, C ... Z, 1, 2, 3 ... 9, 구, 결, ...

В настоящее время я знаю, как сортировать элементы только в алфавитном порядке. Предложения?

NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
        [dataController setSortDescriptors: [NSArray arrayWithObject: sort]];

Ответы [ 5 ]

10 голосов
/ 23 ноября 2011

Вы можете использовать sortedArrayUsingComparator, чтобы настроить алгоритм сортировки в соответствии с вашими потребностями. Например, вы можете дать приоритет символам с такими строками:

NSArray *assorted = [@"1 2 3 9 ; : 구 , 결 A B C Z ! á" 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];         
}];

Чтобы поставить английские символы перед неанглийскими , достаточно использовать NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch в качестве параметров, причудливый алгоритм не требуется.

Если вам нужна поддержка iOS без блоков, попробуйте sortedArrayUsingSelector.

4 голосов
/ 30 апреля 2012

Другое решение путем проверки, является ли строка кодируемой латиницей:

  • проверка для обеих строк, если первый символ является латинским (иначе английским) символом
  • если оба значения совпадают, проверьте, начинается ли оба с буквы или цифры. В обоих случаях оставьте значение compare:
  • иначе, если один начинается с цифры, а другой - с буквы, return NSOrderingAscending, если один начинается с буквы, иначе NSOrderingDescending

  • Если обе строки не являются латинскими, пусть compare: решит снова

  • если латиноамериканец, а другой нет, return NSOrderingAscending, если латиноамериканец первый, иначе NSOrderingDescending

код

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);

результат

ananas
apple
banana
papaya
peach
1
4
5
7
구
결
3 голосов
/ 23 ноября 2011

Я не думаю, что вы можете выполнить такую ​​сортировку без определения собственной функции сравнения.

Для этой цели вы можете использовать sortedArrayUsingFunction :

[array sortedArrayUsingFunction:f context:userContext];

, где f определяется как:

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;
}

Если вы предпочитаете не создавать функцию для этого, вы можете использовать блочную версию метода, sortedArrayUsingComparator :

[array sortedArrayUsingComparator: ^(id obj1, id obj2) {
                                             return NSOrderedSame;
                                   }];
1 голос
/ 23 ноября 2011

Дескриптор сортировки, основанный на компараторе, должен справиться (примечание: не проверено).

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];

Вы, конечно, должны определить свой собственный алгоритм порядка сортировки - но этот пример должен показать, как использоватьдескриптор сортировки для контроллера массива.

0 голосов
/ 26 апреля 2017

Не хватает одного правильного ответа на вопрос: NSNumericSearch

NSArray *assorted = [@"1 2 3 9 ; : 구 , 결 A B C Z ! á" 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]|;         
}];
...