2012-04-25 30 views
5

Jaki jest właściwy sposób odczytu pliku tekstowego do tablicy linii? Znalazłem następujące na Rosetta Stone:odczytać plik z tablicy linii w d

string[] readLines(string filename) { 
    auto f = File(filename); 
    scope(exit) f.close(); 
    string[] lines; 

    foreach (str; f.byLine) { 
    lines ~= str.idup; 
    } 

    return lines; 
} 

ale wygląda na to, że robi jedną macierz rozmiaru na wiersz, który jest bardzo nieefektywne. Mogę śledzić liczby linii odczytać i zmienić rozmiar tablicy poprzez standardową metodą podwojenia

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; 

ale to wystarczy kod boilerplate że muszę się zastanawiać, czy nie jestem tylko wychodzi coś w standardowej biblioteki już to robi dla mnie.


Edit: podając komentarz lepszą widoczność fwend za: this article opisuje szczegółowo jak działa tablica podzielnika i dlaczego Dołączanie jest dobrze obsługiwane przez środowisko wykonawcze

Odpowiedz

4

Właściwie D podwoi tablicy za zarezerwowane miejsce ilekroć zabrakło miejsca, więc nie musisz tego robić ręcznie. Istnieje wiele informacji na temat D's tablicami here

+1

Przeczytałem to i nie powiedziałem nic o wewnętrznej strategii zmiany rozmiaru przy dołączaniu do tablicy –

+0

Tak, właśnie to zauważyłem, ale wiem, że to działa. Aby uzyskać więcej szczegółów, D faktycznie przydziela pamięć w porcjach o potędze-dwóch rozmiarach, więc jeśli tablica będzie większa niż, powiedzmy, 32 bajty, wówczas ponownie przydzieli do porcji o wielkości 64 bajtów. – ricochet1k

+0

dobra, dziękuję, dobrze wiedzieć. –

4

Prawdopodobnie dostanie dużo przesunięć początkowo, ale jako tablica rośnie, jego pojemność powinna wzrosnąć tak, że jest to mniej prawdopodobne, aby przeznaczyć z dalszego dopisywania. Możesz wydrukować właściwość capacity macierzy, aby zobaczyć, jak ona rośnie.

Jeśli jesteś szczególnie martwi się o dołączenie krytyki, to należy prawdopodobnie użyć std.array.Appender, w którym to przypadku, Twój kod będzie wyglądał tak:

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 ma na celu dodanie bardziej wydajne i wykorzysta wszelkie możliwe sztuczki, aby dołączanie było skuteczniejsze niż samo.

4

Może to:

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

To powinno być na tyle szybko, ponieważ wynik jest tylko tworzenie kromki załadowanego wejściowego łańcucha i nie przydzielenie nowych tablic (oprócz przydziału plastry siebie, IOW wskaźnika + długości pola).

Powiązane problemy