如何将NSArray按字母顺序分成UITableView的部分

5
我在使用带有分组标题的索引表格时遇到了麻烦。目前,我已经将索引放在右侧,并且我已经正确地显示了分组标题,只有在该分组内有数据时才会显示标题。
我遇到的问题是将NSArray拆分成几部分,以便我可以正确计算每个分组中的行数。目前,我显示了正确数量的分组和正确的标题,但所有数据都在每个分组中,而不是根据名称的第一个字母进行分割。
以下是当前的屏幕截图:All of the data goes into each sections, 5 rows in each. The number of sections (3) is correct 所有数据都进入了每个分组,每个分组中有5行。分组数(3)是正确的。
我的代码如下:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [firstLetterArray objectAtIndex:section];
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{

    NSMutableSet *mySet = [[NSMutableSet alloc] init];

    BRConnection *connection = nil;
    NSMutableArray *firstNames = [[NSMutableArray alloc] init];
    for (connection in _connections)
    {
        [firstNames addObject:connection.firstName];
    }
    firstNamesArray = firstNames;
    NSLog(@"%@", firstNamesArray);
    for ( NSString *s in firstNames)
    {
        if ([s length] > 0)
            [mySet addObject:[s substringToIndex:1]];
    }

    NSArray *indexArray = [[mySet allObjects] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

    firstLetterArray = indexArray;

    return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {

    if ([title isEqualToString:@"{search}"])
    {
        [tableView setContentOffset:CGPointMake(0.0, -tableView.contentInset.top)];
        return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
    }
    return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"ConnectionCell"];

    // Display connection in the table cell
    BRConnection *connection = nil;
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        connection = [searchResults objectAtIndex:indexPath.row];
    } else {
        connection = [_connections objectAtIndex:indexPath.row];
    }

    cell.textLabel.text = connection.fullName;
    cell.textLabel.font = [UIFont fontWithName:@"TitilliumText25L-400wt" size:18];
    cell.detailTextLabel.text = connection.company;
    cell.detailTextLabel.font = [UIFont fontWithName:@"TitilliumText25L-400wt" size:12];

    return cell;
}


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    NSUInteger sections = [firstLetterArray count];
    return sections;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return [searchResults count];

    } else {
        return [_connections count];
    }
}

任何帮助都将不胜感激,我似乎无法将NSArray conenctions拆分成按字母顺序排列的列表,以获取部分中的正确行。提前感谢大家!

我会考虑将我的后备结构制作成一个数组字典。给定一个键,它将是一个部分的名称,你可以检索匹配的连接数组并返回其计数。 - Phillip Mills
1
@PhillipMills - 一个数组的数组是更好的选择,因为部分是有序的,而字典则不是。 - danh
@danh 我在这两种方法之间犹豫不决。这个案例基本上是字典使用的教科书式范例。毕竟它本质上就是一个字典!但这会使表格填充变得有点复杂。另一方面,使用数组会使排序变得有点复杂。 - Lyndsey Scott
我的一个问题可以帮助您将数据源/NSArray按正确的A-Z格式排序:http://stackoverflow.com/questions/23964377/sort-nsarray-of-nsdictionaries-using-comparator 回答者的回答非常棒! - klcjr89
@troop231,我认为可以比那个更简单地完成...我会尝试写出一个答案... - Lyndsey Scott
@danh 实际上,既然他已经有了一个firstLetterArray数组,也许使用字典并不是一个坏主意,因为已经有了记录的顺序。但在我的答案中,我使用了一个数组的数组,因为即使没有firstLetterArray,它也可以工作...我今天稍后可能会回来看看... - Lyndsey Scott
3个回答

7
你是在哪里以及如何填充“_connections”数组的?你正在使用该数组来确定每个部分的行数并填充这些行,但“_connections”返回整个列表。你需要按字母表顺序拆分“_connections”中的数据。
例如,你可以使用一个NSMutableArray的NSMutableArray来按字母分组数据。由于你已经似乎知道如何按字母表顺序排序,现在你只需要识别每个字符串的第一个字符以正确分组它们。为此,请尝试:
NSString *currentPrefix;

// Store sortedConnections as a class variable (as you've done with _connections)
// so you can access it to populate your table
sortedConnections = [[NSMutableArray alloc] init];

// Go through each connection (already ordered alphabetically)
for (BRConnection *connection in _connections) {

    // Find the first letter of the current connection
    NSString *firstLetter = [connection.fullName substringToIndex:1];

    // If the last connection's prefix (stored in currentPrefix) is equal
    // to the current first letter, just add the connection to the final
    // array already in sortedConnections
    if ([currentPrefix isEqualToString:firstLetter]) {
        [[sortedConnected lastObject] addObject:connection];
    }

    // Else create a new array in sortedConnections to contain connections starting
    // with this current connection's letter.
    else {
        NSMutableArray *newArray = [[NSMutableArray alloc] initWithObject:connection];
        [sortedConnections addObject:newArray];
    }

    // To mark this latest array's prefix, set currentPrefix to contain firstLetter
    currentPrefix = firstLetter;
}

即使第一个字母未知,此排序方法仍可使用。

然后,为了获得每个部分的行数,请使用 [sortedConnections objectAtIndex:section] 替代 _connections:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return [[sortedSearchResults objectAtIndex:section] count]; // hypothetically
    } else {
        return [[sortedConnections objectAtIndex:section] count];
    }
}

为了填充表格,基本上可以使用[sortedConnections objectAtIndex:indexPath.section]进行相同的操作:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"ConnectionCell"];

    // Display connection in the table cell
    BRConnection *connection = nil;
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        connection = [[sortedSearchResults objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]; // hypothetically
    } else {
        connection = [[sortedConnections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
    }

    cell.textLabel.text = connection.fullName;
    cell.textLabel.font = [UIFont fontWithName:@"TitilliumText25L-400wt" size:18];
    cell.detailTextLabel.text = connection.company;
    cell.detailTextLabel.font = [UIFont fontWithName:@"TitilliumText25L-400wt" size:12];

    return cell;
}

我将这个代码放入我的项目中,但是在设置单元格的textLabel时遇到了问题。我被告知NSArray sortedConnections没有选择器fullName,但是当我调试时,我可以看到它确实存在。我不确定应该在答案的第一部分的哪里放置代码,所以我将其放在设置_connections值之后的同一个方法中。有什么想法吗?谢谢。 - adamtrousdale
我尝试使用您指定的两种方法,第二个cell.textLabel.text = [sortedConnections objectAtIndex:section].fullName不能编译。但编译器也不允许我在objectAtIndex中使用section,我将其更改为objectAtIndex:indexPath.row,但我不确定这是否正确,因为它仍然无法正常工作,并且仍告诉我fullName未被识别。而且,这一行connection = [[sortedConnections objectAtIndex:section] objectAtIndex:indexPath.row]不起作用,因为未定义section。应该使用section变量吗? - adamtrousdale
cell.textLabel.text = [sortedConnections objectAtIndex:section].fullName 是错误的。请尝试使用我上面写的代码。对不起,我复制粘贴时有些马虎。在 cellForRowAtIndexPath 中,section 应该改为 indexPath.section。已经修改。 - Lyndsey Scott
@LyndseyScott +1,非常周到和注释详细的回答。有几个建议 - 不要使索引依赖于排序输入,甚至可以从外部集合开始作为一个集合,然后最终作为一个数组,按每个内部数组中第一个对象的第一个字母排序。此外,使用现代的array[index]语法可以缩短代码并增加可读性。最后,获取第一个字母的更好方法是substringToIndex:1。 - danh
我考虑了一下,认为按照我指定的方式进行预排序实际上会更有效率,因为如果在将连接插入数组时动态地进行排序,算法将至少需要进行一次二分排序,并在确定正确的数组时进行单独的二分排序。 - Lyndsey Scott
显示剩余5条评论

5
希望这能对您有所帮助,我不知道这是否是最好的方法,但它有效 =)
NSArray *names = @[@"Ana Carolina", @"Ana carolina", @"Ana luiza", @"leonardo", @"fernanda", @"Leonardo Cavalcante"];

NSMutableSet *firstCharacters = [NSMutableSet setWithCapacity:0];
for( NSString*string in names ){
    [firstCharacters addObject:[[string substringToIndex:1] uppercaseString]];
}
NSArray *allLetters = [[firstCharacters allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
int indexLetter = 0;
NSMutableArray *separeNamesByLetters = [NSMutableArray new];



for (NSString *letter in allLetters) {
    NSMutableDictionary*userBegeinsWith = [NSMutableDictionary new];
    [userBegeinsWith setObject:letter forKey:@"letter"];
    NSMutableArray *groupNameByLetters = [NSMutableArray new];
    NSString *compareLetter1 = [NSString stringWithFormat:@"%@", allLetters[indexLetter]];
    for (NSString*friendName in names) {
        NSString *compareLetter2 = [[friendName substringToIndex:1] uppercaseString];

        if ( [compareLetter1 isEqualToString:compareLetter2] ) {
            [groupNameByLetters addObject:friendName];
        }
    }
    indexLetter++;
    [userBegeinsWith setObject:groupNameByLetters forKey:@"list"];
    [separeNamesByLetters addObject: userBegeinsWith];
}



NSLog(@"%@", separeNamesByLetters);

输出:

 (
        {
        letter = A;
        list =         (
            "ana carolina",
            "Ana carolina",
            "Ana luiza"
        );
    },
        {
        letter = F;
        list =         (
            fernanda
        );
    },
        {
        letter = L;
        list =         (
            leonardo,
            "Leonardo Cavalcante"

        )
    }
)

0

如果您有自定义对象,在@Leo中进行小修改

NSMutableSet *firstCharacters = [NSMutableSet setWithCapacity:0];
        for( ETUser *user in self.follwings){
            [firstCharacters addObject:[[user.name substringToIndex:1] uppercaseString]];
        }
        NSArray *allLetters = [[firstCharacters allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
        int indexLetter = 0;
        NSMutableArray *separeNamesByLetters = [NSMutableArray new];


        for (NSString *letter in allLetters) {

            NSMutableDictionary*userBegeinsWith = [NSMutableDictionary new];

            [userBegeinsWith setObject:letter forKey:@"letter"];

            NSMutableArray *groupNameByLetters = [NSMutableArray new];

            NSString *compareLetter1 = [NSString stringWithFormat:@"%@", allLetters[indexLetter]];

            for (ETUser *user in self.follwings) {

                NSString *compareLetter2 = [[user.name substringToIndex:1] uppercaseString];

                if ( [compareLetter1 isEqualToString:compareLetter2] ) {

                    [groupNameByLetters addObject:user];
                }
            }
            indexLetter++;
            [userBegeinsWith setObject:groupNameByLetters forKey:@"list"];
            [separeNamesByLetters addObject: userBegeinsWith];
        }

        self.follwings = [[NSMutableArray alloc]initWithArray:separeNamesByLetters];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接