2012-04-25 11 views
5

Qual è il modo corretto di leggere un file di testo in una serie di linee? Ho trovato quanto segue su Rosetta Stone:legge un file in una serie di linee in d

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

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

    return lines; 
} 

ma sembra che sta facendo un array ridimensionare per riga, che è piuttosto inefficiente. Potrei tenere traccia del numero di linee leggere e ridimensionare la matrice tramite il metodo raddoppio standard di

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; 

ma basta codice standard che mi chiedo se non sto solo si affaccia qualcosa nella libreria standard che lo fa già per me.


Edit: dare commentare maggiore visibilità del fwend: this article descrive in dettaglio come le opere di matrice allocatore, e perché l'accodamento è gestito in modo efficiente dal runtime

risposta

4

In realtà, D raddoppierà spazio riservato della matrice ogni volta finisce fuori dalla stanza, quindi non hai bisogno di farlo a mano. C'è un sacco di informazioni sugli array di D'here

+1

l'ho letto e non ha detto nulla sulla strategia di ridimensionamento interno durante l'aggiunta a un array –

+0

Sì, lo stavo solo notando, ma so che è come funziona. Per ulteriori dettagli, D assegna effettivamente memoria in blocchi di potenza di due dimensioni, quindi se l'array diventa più grande di, diciamo, 32 byte, verrà riallocato in un blocco di 64 byte. – ricochet1k

+0

ok, grazie, è bello sapere –

4

Probabilmente otterrete molte riallocazioni inizialmente, ma man mano che l'array cresce, la sua capacità dovrebbe crescere in modo tale che sia meno probabile allocarla con ulteriori aggiunte. È possibile stampare la proprietà della serie capacity per vedere come cresce.

Se siete particolarmente preoccupati per aggiungendo prestazioni, tuttavia, allora probabilmente si dovrebbe usare std.array.Appender, in questo caso, il codice sarebbe simile a questa:

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 è progettato per rendere più efficiente aggiungendo e sfrutterà qualsiasi trucco per rendere l'aggiunta più efficiente di ~= da sola.

4

Forse questo:

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

Dovrebbe essere abbastanza veloce in quanto risultato è solo creando fette della stringa di input precaricato e non assegnare nuovi array (a parte la ripartizione delle fette stessi, IOW il puntatore + lunghezza campi).