daw*_*awg 18 python objective-c nsstring
我对Python 中这个用于循环遍历大词列表的算法的小例子感兴趣.我正在写一些"工具",这将允许我以与Python类似的方式切片Objective-C字符串或数组.
具体来说,这个优雅的解决方案引起了我的注意,非常快速地执行,它使用字符串切片作为算法的关键元素.尝试解决这个没有切片!
我使用下面的Moby单词列表复制了我的本地版本./usr/share/dict/words
如果您不想下载Moby,可以使用.源只是一个类似于字典的大型独特单词列表.
#!/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
Run Code Online (Sandbox Code Playgroud)
这个脚本将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;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
因为utf-8与utf-8 NSString在同一平面上.这使Python的速度降低到1.9秒.
我还将切片测试切换为短路类型,如Python和obj-c版本所建议的那样.现在他们接近相同的速度.我也尝试使用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]];
}
Run Code Online (Sandbox Code Playgroud)
现在我终于可以声称Objective-C版本比Python版本更快 - 但不是很多.
请记住,在Python版本已经被写入时对CPython的执行(尤其是文件输入缓冲,字符串的切片和哈希表查找,以检查是否有很多繁重向下移动到高度优化的C代码even
,并odd
在words
).
也就是说,您似乎在Objective-C代码中将文件解码为UTF-8,但在Python代码中将文件保留为二进制文件.在Objective-C版本中使用Unicode NSString,但是Python版本中的8位字节字符串实际上并不是一个公平的比较 - 如果您曾经使用codecs.open()
声明的文件打开文件,我会期望Python版本的性能显着下降编码"utf-8"
.
您还要进行完整的第二遍以去除Objective-C中的空行,而Python代码中不存在此类步骤.