3 Stimmen

Schnelle und effiziente Methode zum Einlesen einer durch Leerzeichen getrennten Zahlendatei in ein Array?

Ich brauche eine schnelle und effiziente Methode, um eine durch Leerzeichen getrennte Datei mit Zahlen in ein Array zu lesen. Die Dateien sind auf diese Weise formatiert:

4 6
1 2 3 4 5 6
2 5 4 3 21111 101
3 5 6234 1 2 3
4 2 33434 4 5 6

Die erste Zeile ist die Dimension des Arrays [Zeilen Spalten]. Die folgenden Zeilen enthalten die Daten des Arrays.

Die Daten können auch ohne Zeilenumbrüche wie folgt formatiert werden:

4 6
1 2 3 4 5 6 2 5 4 3 21111 101 3 5 6234 1 2 3 4 2 33434 4 5 6

Ich kann die erste Zeile lesen und ein Array mit den Zeilen- und Spaltenwerten initialisieren. Dann muss ich das Array mit den Datenwerten füllen. Meine erste Idee war, die Datei Zeile für Zeile zu lesen und die Split-Funktion zu verwenden. Aber das zweite aufgeführte Format lässt mich zögern, da die gesamten Array-Daten auf einmal in den Speicher geladen werden würden. Einige dieser Dateien sind mehrere 100 MB groß. Die zweite Methode wäre, die Datei in Stücken zu lesen und sie dann Stück für Stück zu analysieren. Vielleicht hat jemand anderes eine bessere Methode dafür?

0voto

luke Punkte 13862

Sie möchten die Datei in den Speicher streamen und während der Bearbeitung analysieren.

private IEnumerable<String> StreamAsSpaceDelimited(this StreamReader reader)
{
    StringBuilder builder = new StringBuilder();
    int v;
    while((v = reader.Read()) != -1)
    {
        char c = (char) v;
        if(Char.IsWhiteSpace(c))
        {
            if(builder.Length >0)
            {
                yield return builder.ToString();
                builder.Clear();
            }
        }
        else
        {
            builder.Append(c);
        }
    }
    yield break;
}

wird die Datei in eine Sammlung von durch Leerzeichen getrennten Zeichenketten zerlegt ( faul ) und dann können Sie sie als Doppelgänger lesen, genau wie :

using(StreamReader sr = new StreamReader("filename"))
{
    var nums = sr.StreamAsSpaceDelimited().Select(s => int.Parse(s));
    var enumerator = nums.GetEnumerator();
    enumerator.MoveNext();
    int numRows = enumerator.Current;
    enumerator.MoveNext();
    int numColumns = enumerator.current;
    int r =0, c = 0;
    int[][] destArray = new int[numRows][numColumns];
    while(enumerator.MoveNext())
    {
        destArray[r][c] = enumerator.Current;
        c++;
        if(c == numColumns)
        {
            c = 0;
            r++;
            if(r == numRows)
               break;//we are done
        }
    }

Da wir Iteratoren verwenden, sollten nie mehr als ein paar Zeichen auf einmal gelesen werden. Dies ist ein üblicher Ansatz, um große Dateien zu parsen (zum Beispiel so LINQ2CSV funktioniert).

0voto

Anthony Pegram Punkte 119149

Hier sind zwei Methoden

IEnumerable<int[]> GetArrays(string filename, bool skipFirstLine)
{
    using (StreamReader reader = new StreamReader(filename))
    {
        if (skipFirstLine && !reader.EndOfStream)
            reader.ReadLine();

        while (!reader.EndOfStream)
        {
            string temp = reader.ReadLine();
            int[] array = temp.Trim().Split().Select(s => int.Parse(s)).ToArray();
            yield return array;
        }
    }
}

int[][] GetAllArrays(string filename, bool skipFirstLine)
{
    int skipNumber = 0;
    if (skipFirstLine )
        skipNumber = 1;
    int[][] array = File.ReadAllLines(filename).Skip(skipNumber).Select(line => line.Trim().Split().Select(s => int.Parse(s)).ToArray()).ToArray();
    return array;
}

Wenn Sie es mit großen Dateien zu tun haben, ist die erste Option wahrscheinlich vorzuziehen. Wenn die Dateien klein sind, kann die zweite Methode das Ganze in ein zackiges Array laden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X