2012-04-25 29 views
5

什麼是閱讀文本文件轉換成線的陣列的正確方法數組?我發現下面的羅塞塔石碑:文件讀入行的d

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詳細介紹瞭如何數組分配工作,爲什麼追加有效地運行時

回答

4

實際處理時,d將增加一倍陣列的保留空間,只要它用完了房間,所以你不需要手工完成。有很多關於D的陣列的信息here

+1

我通讀了這篇文章,並且在追加到數組時沒有提到有關內部調整大小策略的任何內容 – 2012-04-25 05:54:36

+0

是的,我只是注意到了這一點,但我知道它是如何工作的。更詳細地說,D實際上是以兩個冪的大小來分配內存,所以如果數組的增長大於32個字節,則它將重新分配爲64個字節的塊。 – ricochet1k 2012-04-25 05:56:01

+0

好的,謝謝,很高興知道 – 2012-04-25 05:56:36

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

它應該足夠快,因爲結果只是創造預裝的輸入字符串的切片,而不是從切片的分配分配新陣列(除了自己,督察指針+長度字段)。