根据联系人姓名获取sectionIndex标题

Get sectionIndex titles based on contact name

在我的应用程序中,我有一个包含 50k+ 联系人的数据库。要在列表视图中显示它们,我需要计算索引部分标题以在右侧显示它们。

但是我的逻辑需要大约 3-6 秒的时间来准备数据源。

-(NSArray *)getSectionTitleBasedOn:(NSString*)sortBy{

    for (RealmContact *contact in contactSource){

        if (contact.firstName.length>0) {
            if ([sortBy isEqualToString:@"FirstName"]) {

                NSString *firName= [contact.firstName stringByReplacingOccurrencesOfString:@" " withString:@""];
                NSString *regex = @"^[A-Za-z]+";
                NSPredicate *test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
                BOOL result = [test evaluateWithObject:firName];

                if (contact.firstName.length>0 && result)
                {
                    [nameDic setObject:@"firstletter" forKey:[[contact.firstName substringToIndex:1]uppercaseString]];
                }else{
                     [nameDic setObject:@"firstletter" forKey:@"#"];
                }
            }
            if ([sortBy isEqualToString:@"LastName"]) {
                //same
            }
            if ([sortBy isEqualToString:@"Company"]) {
                //same
            }

        }
    }
    NSLog(@"dic %@",nameDic);
    return [[nameDic allKeys]sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}

我想知道我是否可以做些什么来改进它。

 NSString *firName= [contact.firstName stringByReplacingOccurrencesOfString:@" " withString:@""];
 NSString *regex = @"^[A-Za-z]+";
  NSPredicate *test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
  BOOL result = [test evaluateWithObject:firName];

我这样做是为了检查字符串是否包含特殊字符或无效字符。

得到数组后,我对它进行排序,return 数组。输出将是:

dic {
    "#" = firstletter;
    A = firstletter;
    B = firstletter;
    C = firstletter;
    D = firstletter;
    E = firstletter;
    F = firstletter;
    G = firstletter;
    H = firstletter;
    I = firstletter;
    J = firstletter;
    K = firstletter;
    L = firstletter;
    M = firstletter;
    N = firstletter;
    O = firstletter;
    P = firstletter;
    Q = firstletter;
    R = firstletter;
    S = firstletter;
    T = firstletter;
    U = firstletter;
    V = firstletter;
    W = firstletter;
    X = firstletter;
    Y = firstletter;
    Z = firstletter;
}

我这样做了:

NSArray *sortedLetters = nil;
NSMutableSet *set = [[NSMutableSet alloc] init];
NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@"AZERTYUIOPQSDFGHJKLMWXCVBN"];
for (RealmContact *contact in _dataSource)
{
    NSString *firName = [[contact firstName] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    if ([firName length])
    {
        unichar c = [[firName uppercaseString] characterAtIndex:0];
        if ([charSet characterIsMember:c])
        {
            [set addObject:[NSString stringWithFormat: @"%C", c]];
        }
        else
        {
            [set addObject:@"#"];
        }
    }
}
sortedLetters = [[set allObjects] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

有什么区别?
• 我使用 NSSet 而不是 NSDictionary 来表示第一个字母的唯一性。我发现使用具有未使用值的 NSDictionary 是没有用的,只是为了键的唯一性。
• 我使用stringByTrimmingCharactersInSet: 而不是stringByReplacingOccurrencesOfString:withString:。理论上,stringByTrimmingCharactersInSet: 的代码应该在第一个不属于集合的字符处停止,并且不会继续到字符串的末尾,如 stringByReplacingOccurrencesOfString:withString:.
• 我猜 characterIsMember: 比 Regex/Predicate 快。
• 由于您只对大写字母感兴趣,我在进行测试之前翻译了它,而不是之后,这也可以加快您案例中的谓词。

此外,您的代码中存在一些小错误:

if (contact.firstName.length>0 && result) 

[nameDic setObject:@"firstletter" forKey:[[contact.firstName substringToIndex:1]uppercaseString]]; 

应该使用firName而不是contact.firstName

this test sample,我的解决方案似乎比你的 (x10) 快。 我在 OS X App(不是 iOS)上进行了快速测试。我没有做很多测试,但可能值得一试。

不知道是不是为了问题,但是,你可以做的代码优化:

NSString *stringToTest = nil;
if ([sortBy isEqualToString:@"FirstName"]) 
{
    stringToTest = contact.firstName;
}
else if ([sortBy isEqualToString:@"LastName"]) 
{
    stringToTest = contact.lastName;
}
else if ([sortBy isEqualToString:@"Company"]) 
{
    stringToTest = contact.companyName;
}
stringToTest = [stringToTest stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];    
if ([stringToTest length])
{
    //Do the code with stringToTest
}

这是为了减少代码重复,同时也使用了if/else