从文本文件中读取行,如果值匹配

时间:2017-06-09 17:48:11

标签: linq c#-4.0 filestream

我有一个有几千行的文本文件。每行都是学生,并测试各种测试的分数。并非所有学生都有相同数量的测试(即行)。我需要将文件分成更小的块,但我不想分解任何一组学生分数。由于主文件已经排序,因此不需要排序,但我们会对其进行排序。

假设我希望chunk至少有5行,但如果第6行与第5行是同一个学生,那么将第6行添加到chunk中。等等,直到学生改变。

然后,启动一个新的块(带有标题,但这部分很容易),直到到达原始文件的末尾。

我可以使用linq或FileStream,只要我有每个块,我将通过API将其加载到应用程序中。

以下是主文件的简化示例:

STUDENT_ID    TEST    SCORE
000001          A       10
000001          B       10
000001          C       10
000001          D       10
000002          A       10
000002          B       10
000002          C       10
000002          D       10
000003          A       10
000003          B       10
000004          C       10
000004          D       10
000004          E       10
000004          F       10

所以,第一个块看起来像:

STUDENT_ID    TEST    SCORE
000001          A       10
000001          B       10
000001          C       10
000001          D       10
000002          A       10
000002          B       10
000002          C       10
000002          D       10

到目前为止,我已经完成了一个使用常量" rowsToTake" = 5,一个子串(0,6),用于比较所采取的第5行的STUDENT_ID和" currentPosition"每次拍摄时增加。我在外环上失去了动力,获得了后续的块。到目前为止,我选择不发布我的代码,因为我不认为它很好,我也不希望任何人觉得他们应该建立它。

2 个答案:

答案 0 :(得分:0)

我认为LINQ解决方案不适合您的场景。我更喜欢使用for循环,相应地比较文本文件中每行的内容。

伪码:

string previousStudentID = null;
List<...> chunk = new List<...>();
foreach (string line in file)
{
    string studentID = // parse studentID from line

    if (studentID != previousStudentID && chunk.Count > 5)
    {
        // add header to beginning of chunk
        // load chunk to API

        chunk.Clear(); // clear/create a new chunk
    }

    // add line to chunk

    previousStudentID = studentID;
}

// load remaining header/chunk to API, if necessary

答案 1 :(得分:0)

使用LINQ按学生ID分组效率不高,所以在行中处理似乎更好。

public class TestRecord {
    public string line;
    public string StudentID;

    public TestRecord(string _line) {
        line = _line;
        StudentID = Regex.Split(line, @"\s+")[0];
    }
}

public IEnumerable<TestRecord> ReadRecords(string filename) {
    var fileInput = File.ReadLines(filename);

    foreach (var line in fileInput)
        yield return new TestRecord(line);
}

void Main() {
    var filePath = @"file folder\";
    var recordInput = ReadRecords($"{filePath}students.txt");
    var inputEnumerator = recordInput.GetEnumerator();

    // get header line
    inputEnumerator.MoveNext();
    var headerLine = inputEnumerator.Current.line;
    inputEnumerator.MoveNext();

    var chunkSize = 5;

    var outFileCount = 0;
    var chunkSoFar = 0;
    StreamWriter outFile = null;
    bool moreInput;
    do {
        if (chunkSoFar >= chunkSize || chunkSoFar == 0) { // start new chunk
            outFile?.Close();
            outFile = new StreamWriter($"{filePath}chunk{++outFileCount:D4}.txt".Dump());
            outFile.WriteLine(headerLine.Dump());
            chunkSoFar = 0;
        }
        string curStudentID = inputEnumerator.Current.StudentID;
        do {
            outFile.WriteLine(inputEnumerator.Current.line.Dump());
            ++chunkSoFar;
        } while ((moreInput = inputEnumerator.MoveNext()) && inputEnumerator.Current.StudentID == curStudentID);
    } while (moreInput);
    outFile.Close();
}