Question

I have a huge word list of over 280.000+ words that is loaded from an sqlite database to an NSArray. then I do a fast enumeration to check if a certain string value entered by the user matches one of the words in the Array. Since the array is so large it takes about 1-2 seconds on the iphone 4 to go through that array.

How can I improve the performance? Maybe I should make several smaller arrays? one for each letter in the alphabet so that there is less data to go through.

this is how my database class looks

static WordDatabase *_database;

+(WordDatabase *) database
{

    if (_database == nil) {

        _database = [[WordDatabase alloc] init];

    }

    return _database;
}

- (id) init
{
    if ((self = [super init])) {
        NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:@"dictionary" ofType:@"sqlite"];


        if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
            NSLog(@"Failed to open database!");
        }
    }
    return self;

}

- (NSArray *)dictionaryWords {

    NSMutableArray *retval = [[[NSMutableArray alloc] init] autorelease];
    NSString *query = @"SELECT word FROM words";
    sqlite3_stmt *statement;

    if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
        while (sqlite3_step(statement) == SQLITE_ROW) {

            char *wordChars = (char *) sqlite3_column_text(statement, 0);

            NSString *name = [[NSString alloc] initWithUTF8String:wordChars];

            name = [name uppercaseString];

            [retval addObject:name];

        }
        sqlite3_finalize(statement);
    }

    return retval;

}

then in my main view I initialise it like this

dictionary = [[NSArray alloc] initWithArray:[WordDatabase database].dictionaryWords];

and finally I go through the array using this method

- (void) checkWord
{    
    NSString *userWord = formedWord.wordLabel.string;
    NSLog(@"checking dictionary for %@", userWord);

    for (NSString *word in dictionary) {
        if ([userWord isEqualToString: word]) {   
        NSLog(@"match found");    
        }     
    }
}
Was it helpful?

Solution

Lots of different ways.

  • stick all the words in a dictionary or set, testing for presence is fast

  • break it up as you suggest; create a tree type structure of some kind.

  • use the database to do the search. They are generally pretty good at exactly that, if constructed correctly.

OTHER TIPS

If space isn't an issue, store a hash value of each word and use that for your base lookup. Once filtered by the hash, then compare each of the words. This will reduce the number of costly string comparisons. Easier to index/sort and performs quick lookups.

I second a dictionary. NSDictionary for objective c.

for instance:

// To print out all key-value pairs in the NSDictionary myDict

 for(id key in myDict)
    NSLog(@"key=%@ value=%@", key, [myDict objectForKey:key]);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top