在D语言中将文件读入行数组

5

什么是将文本文件正确读入行数组的方法?我在 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的评论:这篇文章详细描述了数组分配器的工作原理以及运行时如何高效地处理添加操作。

3个回答

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旨在使附加更有效,并将利用任何技巧使附加比~=本身更有效。


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);
}

这应该足够快,因为结果只是创建预加载输入字符串的切片,而不是分配新数组(除了分配切片本身,即指针+长度字段)。


4
实际上,当D语言的数组空间不足时,它会自动将数组的保留空间加倍,因此您不需要手动执行此操作。关于D语言的数组,有很多信息可以在这里找到。

1
我仔细阅读了那个内容,但它并没有提到在向数组追加元素时的内部调整策略。 - Martin DeMello
是的,我刚注意到这一点,但我知道这就是它的工作方式。更详细地说,D语言实际上会按2的幂分配内存块,因此如果数组增长超过32字节,它将重新分配到64字节大小的内存块中。 - ricochet1k
如果你真的很担心,文档中提到你可以使用Phobos的.capacity属性来确定在需要调整大小之前可用的空间量。 - ricochet1k
4
有另一篇关于 D 语言切片的文章非常有趣。它介绍了分配内存的部分。http://dlang.org/d-array-article.html - fwend

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接