我正在构建一个拼字游戏,并且在单词词典中遇到了一些问题。它包含~70万字,大约18 MB字。
现在,我正在将整个dict加载到一个数组中,在iPhone 4上需要12秒。
wordList = [NSMutableArray arrayWithContentsOfFile: [[self applicationDocumentsDirectory] stringByAppendingString:@"/wordlist.plist"]];
我有两个问题:
有更好的方法可以更快地加载wordlist和/或减少内存吗?
从一组字母中获取所有可能的单词大约需要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;
}
答案 0 :(得分:3)
你需要改变一些事情来加快速度。
使用快速枚举代替旧的C风格循环。
避免大量方法调用。
如果可能,请使用NSPredicate和/或Regex。
每当你编写[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数据库仍然会更快更好。