2012-04-25 14 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; 
} 

それはかなり非効率的である1列の行ごとにサイズを変更し、やっているように見えます:私はロゼッタストーンで次を発見しました。私は中に読み、標準倍増メソッドを介して

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

私はこれを読んで、配列に追加するときに内部サイズ変更の戦略について何も言わなかった。 –

+0

うん、それに気付いていたが、それはどういう仕組みか分かっている。詳細については、Dは実際には2のべき乗の塊でメモリを割り当てます。したがって、配列が32バイトよりも大きくなると、64バイトのチャンクに再割り当てされます。 – ricochet1k

+0

大丈夫、ありがとう、それはよく分かります –

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

結果がちょうどIOWに、離れたスライス自体の割り当てから(ポインタ+長さをプリロード入力文字列のスライスを作成し、新しいアレイを割り当てていないので、それが十分に高速でなければなりませんフィールド)。

関連する問題