IOS文字游戏。验证单词表现

时间:2013-01-15 11:55:06

标签: ios objective-c dictionary word

我正在构建一个拼字游戏,并且在单词词典中遇到了一些问题。它包含~70万字,大约18 MB字。

现在,我正在将整个dict加载到一个数组中,在iPhone 4上需要12秒。

wordList = [NSMutableArray arrayWithContentsOfFile: [[self applicationDocumentsDirectory] stringByAppendingString:@"/wordlist.plist"]];

我有两个问题:

  1. 有更好的方法可以更快地加载wordlist和/或减少内存吗?

  2. 从一组字母中获取所有可能的单词大约需要12秒钟。有可能让它更快吗?这是代码:

    -(NSMutableArray *)getValidWords:(NSString *)letters{
        NSMutableArray *list = [[NSMutableArray alloc] init];
    
        for (int i = 0, c = [wordList count]; i < c; i++){
        if ([self isWordValid: [wordList objectAtIndex: i] forLetters:letters]){
            [list addObject:[wordList objectAtIndex: i]];
        }
    }
    
    return list;
    

    }

    - (BOOL)isWordValid:(NSString *)word forLetters:(NSString *)ltrs{
        int i, z;
        NSRange range;
        BOOL found;
        static NSMutableString *letters = nil;
    
        if ([word length] < 2) return NO;
    
        if(letters == nil) {
            letters = [[NSMutableString alloc] initWithString:ltrs];
        }
        else {
            [letters setString: ltrs];
        }
    
        found = NO;
        range.length = 1;
        for(i = 0; i < [word length]; i++){
            for(z = 0; z < [letters length]; z++){
                if([word characterAtIndex:i] == [letters characterAtIndex:z]){
                     range.location = z;
                     [letters deleteCharactersInRange: range];
                     found = YES;
                     break;
                }
           }
           if (found == NO){
                return NO;
           }
    
           found = NO;
      }
    
      return YES;
    }
    

3 个答案:

答案 0 :(得分:3)

你需要改变一些事情来加快速度。

  1. 使用快速枚举代替旧的C风格循环。

  2. 避免大量方法调用。

  3. 如果可能,请使用NSPredicate和/或Regex。


  4. 每当你编写[letters length]时,就会调用一个方法,而不是找到数百万的时间(这是在嵌套循环的第3级内),将它存储在变量中并使用它。

    快速枚举:取代for(int i=0; i<[someArrays count];i++)使用for(id object in someArrays)

答案 1 :(得分:2)

使用此
[NSThread detachNewThreadSelector:@selector(fetchWords:) toTarget:self withObject:data];

不要在主线程中执行

使用此代码修改它,如果你需要搜索单词

NSMutableArray *subpredicates = [NSMutableArray array];

    for(NSString *term in arryOfWordsToBeSearched) {
        NSPredicate *p = [NSPredicate predicateWithFormat:@"self contains[cd] %@",term];
        [subpredicates addObject:p];
        }

     NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
    result = (NSMutableArray*)[arryOfDummyData filteredArrayUsingPredicate: filter];

// result是一个数组

答案 2 :(得分:2)

对于初学者,请从NSCharacterSet创建letters并在调用冗长函数之前调用此函数。这是一个更快的检查,以减少可能性,它应该会缩短你的计算时间。

NSCharacterSet* lettersSet = [NSCharacterSet characterSetWithCharactersInString:letters];

- (BOOL)isWordValid:(NSString*)word forLettersSet:(NSCharacterSet*)lettersSet {
    if ([word length] < 2) return NO;

    NSCharacterSet* wordLetters = [NSCharacterSet characterSetWithCharactersInString:word];

    return [lettersSet isSupersetOfSet:wordLetters];
}

理想情况下,你的单词数据库应该预先计算每个单词的字母数(例如every = {e=2, r=1, v=1, y=1},你应该只使用这些结构。注意字母的顺序并不重要 - 使用这个事实可以大大改善算法的性能。

您还可以尝试创建核心数据数据库 - 每个单词都是一个记录,每个字母都有一个数字字段。然后你可以创建一个请求,它将非常快速地返回可用的单词。 (当然,数据库可能会占用更多空间)。

编辑:现在我找到了NSCountedSet课程,所以让我们尝试使用它:

-(NSCountedSet*)lettersSetFromString:(NSString*)string {
    NSCountedSet* letters = [NSCountedSet set];
    [string enumerateSubstringsInRange:NSMakeRange(0, self.length)  
                               options:NSStringEnumerationByComposedCharacterSequences   
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        [letters addObject:substring];
    }];
} 

-(NSMutableArray *)validWordsForLetters:(NSString*)letters {
    NSCountedSet* lettersSet = [self lettersSetFromString:letters];

    NSMutableArray* results = [NSMutableArray array];

    for (NSString* word in wordList) {
        if ([word length] < 2) {
            continue;
        }

        NSCountedSet* wordLettersSet = [self lettersSetFromString:word];

        if ([wordLettersSet isSubsetOfSet:lettersSet]) {
            [results addObject:word];
        }
    }

    return results;
}

预先为每个单词生成计数集将有助于提高性能。对于OS内存,使用Core Data数据库仍然会更快更好。