如何按 Objective-C 中最后的数字按字母顺序对数组控制器进行排序?

发布于 2024-12-17 15:38:19 字数 354 浏览 1 评论 0原文

我有一个 NSArrayController ,我想对内容进行排序,以便首先对包含英文字母的任何内容进行排序,然后对包含数字和非英文字符的任何内容进行最后排序。

例如:A,B,C ... Z,1,2,3 ... 9,구,결,...

目前我只知道如何按字母顺序对项目进行排序。建议?

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

I have an NSArrayController and I would like to sort the contents so that anything with English alphabets are sorted first and then anything 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 items in alphabetical order. Suggestions?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

黯然#的苍凉 2024-12-24 15:38:19

您可以使用 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

You can use sortedArrayUsingComparator to customize the sort algorithm to your needs. For instance, you can give precedence to symbols with this lines:

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

To put English characters before non-English ones, it'd be enough to use NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch as options, no fancy algorithm required.

If you need to support iOS without blocks try sortedArrayUsingSelector.

听,心雨的声音 2024-12-24 15:38:19

另一种解决方案是测试字符串是否可编码:

  • 测试两个字符串,如果第一个字符是拉丁(又名英语)字符,
  • 如果两者都是,则测试两者是否以字母或数字开头。在这两种情况下,将其保留在比较中:
  • 否则,如果一个以数字开头,一个以字母开头,则返回 NSOrderingAscending,如果以字母开头,则返回 NSOrderingAscending第一个,否则 NSOrderingDescending

  • 如果两个字符串都不是拉丁字符串,则让 compare: 再次决定

  • 一个是拉丁文,一个不是,如果拉丁文在前,则返回 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
구
결

Another solution by testing, if a string is latin1-encodeable:

  • test for both strings, if the first character is a latin (aka english) character
  • if both are, test if both starts either with a letter or a number. In both cases, leave it up the compare:
  • else, if one starts with the number and one with a letter, return NSOrderingAscending, if the one with letter its first, otherwise NSOrderingDescending

  • If both strings aren't latin, let compare: decide again

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

the 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
구
결
梦途 2024-12-24 15:38:19

我认为如果不定义自己的比较函数就无法进行这种排序。

为此,您可以使用 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;
                                   }];

I don't think you can do that kind of sorting without defining your own comparison function.

To this aim, you could 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 creating function for doing this you could use the block-version of the method, sortedArrayUsingComparator:

[array sortedArrayUsingComparator: ^(id obj1, id obj2) {
                                             return NSOrderedSame;
                                   }];
不弃不离 2024-12-24 15:38:19

基于比较器的排序描述符应该可以解决问题(注意:未经测试)。

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

您当然必须定义自己的排序顺序算法 - 但此示例应该展示如何使用数组控制器的排序描述符。

A sort descriptor based on a comparator should do the trick (note: not tested).

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

You of course have to define your own sort order algorithm - but this example should show how to use a sort descriptor for an array controller.

誰認得朕 2024-12-24 15:38:19

缺少一件事来正确回答这个问题: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]|;         
}];

One thing is missing to answer properly to the question : 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]|;         
}];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文