【发布时间】:2011-04-11 04:46:05
【问题描述】:
我对@987654321@ 的 Python 算法感兴趣,该算法用于遍历一个大的单词列表。我正在编写一些“工具”,它们允许我以与 Python 类似的方式对 Objective-C 字符串或数组进行切片。
具体来说,this elegant solution 执行速度非常快引起了我的注意,它使用字符串切片作为算法的关键元素。尝试解决这个问题!
我已经使用下面的Moby word list 复制了我的本地版本。如果您不想下载 Moby,可以使用/usr/share/dict/words。来源只是一个大型字典式的独特单词列表。
#!/usr/bin/env python
count=0
words = set(line.strip() for line in
open("/Users/andrew/Downloads/Moby/mwords/354984si.ngl"))
for w in words:
even, odd = w[::2], w[1::2]
if even in words and odd in words:
count+=1
print count
此脚本将 a) 由 Python 解释; b) 读取 4.1 MB、354,983 字的 Moby 字典文件; c) 剥线; d) 将线条放入一个集合中,并且; e) 并找出给定单词的偶数和几率也是单词的所有组合。这在 MacBook Pro 上执行大约需要 0.73 秒。
我试图用 Objective-C 重写相同的程序。我是这门语言的初学者,所以请放轻松,但请指出错误。
#import <Foundation/Foundation.h>
NSString *sliceString(NSString *inString, NSUInteger start, NSUInteger stop,
NSUInteger step){
NSUInteger strLength = [inString length];
if(stop > strLength) {
stop = strLength;
}
if(start > strLength) {
start = strLength;
}
NSUInteger capacity = (stop-start)/step;
NSMutableString *rtr=[NSMutableString stringWithCapacity:capacity];
for(NSUInteger i=start; i < stop; i+=step){
[rtr appendFormat:@"%c",[inString characterAtIndex:i]];
}
return rtr;
}
NSSet * getDictWords(NSString *path){
NSError *error = nil;
NSString *words = [[NSString alloc] initWithContentsOfFile:path
encoding:NSUTF8StringEncoding error:&error];
NSCharacterSet *sep=[NSCharacterSet newlineCharacterSet];
NSPredicate *noEmptyStrings =
[NSPredicate predicateWithFormat:@"SELF != ''"];
if (words == nil) {
// deal with error ...
}
// ...
NSArray *temp=[words componentsSeparatedByCharactersInSet:sep];
NSArray *lines =
[temp filteredArrayUsingPredicate:noEmptyStrings];
NSSet *rtr=[NSSet setWithArray:lines];
NSLog(@"lines: %lul, word set: %lul",[lines count],[rtr count]);
[words release];
return rtr;
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int count=0;
NSSet *dict =
getDictWords(@"/Users/andrew/Downloads/Moby/mwords/354984si.ngl");
NSLog(@"Start");
for(NSString *element in dict){
NSString *odd_char=sliceString(element, 1,[element length], 2);
NSString *even_char=sliceString(element, 0, [element length], 2);
if([dict member:even_char] && [dict member:odd_char]){
count++;
}
}
NSLog(@"count=%i",count);
[pool drain];
return 0;
}
Objective-C 版本产生了相同的结果(13,341 个单词),但需要将近 3 秒才能完成。我必须做一些严重错误的编译语言比脚本语言慢 3 倍以上,但如果我能明白原因,我会被诅咒的。
基本算法是相同的:读取线条,剥离它们,然后将它们放在一组中。
我猜慢的是 NSString 元素的处理,但我不知道替代方案。
编辑
我将 Python 编辑成这样:
#!/usr/bin/env python
import codecs
count=0
words = set(line.strip() for line in
codecs.open("/Users/andrew/Downloads/Moby/mwords/354984si.ngl",
encoding='utf-8'))
for w in words:
if w[::2] in words and w[1::2] in words:
count+=1
print count
让 utf-8 与 utf-8 NSString 在同一平面上。这将 Python 减慢到 1.9 秒。
对于 Python 和 obj-c 版本,我还将切片测试切换为短路类型 suggested。现在它们接近相同的速度。我还尝试使用 C 数组而不是 NSStrings,这要快得多,但没那么容易。你也失去了对 utf-8 的支持。
Python 真的很酷……
编辑 2
我发现了一个大大加快速度的瓶颈。我没有使用[rtr appendFormat:@"%c",[inString characterAtIndex:i]]; 方法将字符附加到返回字符串,而是使用了这个:
for(NSUInteger i=start; i < stop; i+=step){
buf[0]=[inString characterAtIndex:i];
[rtr appendString:[NSString stringWithCharacters:buf length:1]];
}
现在我可以终于声称,Objective-C 版本比 Python 版本快——但速度并不快。
【问题讨论】:
-
在阅读了 NSString 之后(请参阅我的建议答案),当您在 Python 版本中使用
codecs.open()时,我很想知道这些数字是多少。 -
Objective C 在看到那个简短的 Python 小程序后确实看起来很丑!
-
Objective-C 有一张只有妈妈才会喜欢的脸,我想...
标签: python objective-c nsstring