我有一个有几千行的文本文件。每行都是学生,并测试各种测试的分数。并非所有学生都有相同数量的测试(即行)。我需要将文件分成更小的块,但我不想分解任何一组学生分数。由于主文件已经排序,因此不需要排序,但我们会对其进行排序。
假设我希望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"每次拍摄时增加。我在外环上失去了动力,获得了后续的块。到目前为止,我选择不发布我的代码,因为我不认为它很好,我也不希望任何人觉得他们应该建立它。
答案 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();
}