Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split NSArray into UITableView sections alphabetically

I have having trouble using an indexed table with section headers. Currently I have the indexes down the right hand side and I have the section headers showing correctly, the headers only show if there is data inside of that section.

The problem I am having is splitting the NSArray into parts so I can calculate the numberOfRowsInSections correctly. Currently I have the correct number of sections displaying with the correct headers but all of the data is in each section, rather than being split depending on the first letter of the name.

Here is a screenshot of how it currently looks:All of the data goes into each sections, 5 rows in each. The number of sections (3) is correct

All of the data goes into each sections, 5 rows in each. The number of sections (3) is correct

My code for this is as follows:

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

Any help would be greatly appreciated, I just cant seem to split the NSArray conenctions into a alphabetical list to get the correct rows in a section. Thanks in advance everyone!

like image 240
adamtrousdale Avatar asked Jun 21 '14 14:06

adamtrousdale


2 Answers

Where and how are you populating _connections? You're using that array to decide the number of rows per section and to populate those rows, but _connectionsis returning the entire list. You need to split the data in _connections up alphabetically.

For example, perhaps you could use an NSMutableArray of NSMutableArrays to group the data by letter. Since you already seem to know how to sort alphabetically, now you just need to identify the first characters of each string to group them properly. To do this, try:

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

(This sort would work even if the first letters are unknown.)

Then to get the number of rows per section, use [sortedConnections objectAtIndex:section] instead of _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];
    }
}

And to populate the table essentially do the same using [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;
}
like image 174
Lyndsey Scott Avatar answered Nov 15 '22 04:11

Lyndsey Scott


Hope that helps you, i don't know if is the best way to do, but it works =)

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

output:

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

        )
    }
)
like image 34
Leonardo Cavalcante Avatar answered Nov 15 '22 04:11

Leonardo Cavalcante