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

Posted

技术标签:

【中文标题】根据联系人姓名获取 sectionIndex 标题【英文标题】:Get sectionIndex titles based on contact name 【发布时间】:2017-08-14 13:38:20 【问题描述】:

在我的应用程序中,我有一个拥有 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];

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

得到数组后,我对其进行排序并返回数组。输出将是:

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;

【问题讨论】:

我这样做了:pastebin.com/ixHsPSxh 在 OSX 模拟器上测试,似乎更快(x10,但没有做更多测试)。此外,代码中的小错误:if (contact.firstName.length>0 && result)[nameDic setObject:@"firstletter" forKey:[[contact.firstName substringToIndex:1]uppercaseString]]; 应使用 firName 而不是 contact.firstName 【参考方案1】:

我这样做了:

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: 比正则表达式/谓词更快。 • 由于您只对大写感兴趣,所以我在进行测试之前而不是之后翻译它,这也可以加快您案例中的谓词。

另外,代码中的小错误:

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

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

应该使用firName 而不是contact.firstName

在this test sample 上,我的解决方案似乎比您的解决方案更快 (x10)。 我在 OS X 应用程序(不是 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 的使用

【讨论】:

感谢您的努力! 出于好奇,在您说您的解决方案需要“3-6 秒”之前。现在?你有足够的进步吗? 现在是即时的。 200k + 联系人需要 2-3 秒。 太棒了!要添加的一个小优化可能是如果您有那么多联系,您可能会认为会有所有字母和其他,那么您可能想做if ([set count] == 27)break;它可能会或不会紧固一点。

以上是关于根据联系人姓名获取 sectionIndex 标题的主要内容,如果未能解决你的问题,请参考以下文章

获取联系人姓名?

获取联系人姓名?

无法获取联系人姓名

如何从联系人列表中获取姓名

使用电话号码获取联系人姓名

如何从android中的联系人姓名获取联系人的号码