将文本文件读入行数组的正确方法是什么?我在Rosetta Stone上找到了以下内容:
string[] readLines(string filename) {
auto f = File(filename);
scope(exit) f.close();
string[] lines;
foreach (str; f.byLine) {
lines ~= str.idup;
}
return lines;
}
但看起来每行调整一个数组,效率非常低。我可以通过标准的双倍方法跟踪读入的行数并调整数组的大小
int i = 0;
foreach (str; f.byLine) {
if (lines.length <= i + 1) {
lines.length = lines.length * 2 + 1;
}
lines[i] = str.idup;
i++;
}
lines.length = i;
但这是足够的样板代码,我不得不想知道我是不是只是忽略标准库中已经为我做过的事情。
编辑:为fwend的评论提供更多可见性:this article详细描述了数组分配器的工作原理,以及运行时有效处理追加的原因
答案 0 :(得分:4)
实际上,只要阵列的空间不足,D就会使阵列的预留空间加倍,所以你不需要手动完成。关于D'数组here
的信息很多答案 1 :(得分:4)
您最初可能会获得大量重新分配,但随着阵列的增长,其容量应该增长,以便通过进一步追加分配的可能性更小。您可以打印出数组的capacity
属性,看它是如何增长的。
但是,如果你特别担心附加性能,那么你应该使用std.array.Appender
,在这种情况下,你的代码看起来像这样:
string[] readLines(string filename)
{
auto file = File(filename);
auto lines = appender!(string[]);
foreach(line; file.byLine())
lines.put(to!string(line));
return lines.data;
}
Appender
旨在提高追加效率,并利用其所能提供的任何技巧使附加效率高于~=
本身。
答案 2 :(得分:4)
也许这个:
import std.algorithm;
import std.array;
import std.file;
string[] readLines(string input)
{
Appender!(string[]) result;
foreach (line; input.splitter("\n"))
result.put(line);
return result.data;
}
void main()
{
string input = cast(string)std.file.read("test.d");
string[] lines = readLines(input);
}
它应该足够快,因为结果只是创建预加载的输入字符串的片段而不分配新的数组(除了片段本身的分配,IOW指针+长度字段)。