Search code examples
c#.net-corecsvhelper

Grouping records together using multiple record types in CsvHelper


I have a large log file containing different record types that I want to parse. It looks something like this:

$L,8,PO
$L,8,SF
$P,8,P,0,102,0,19:08:34.463
$P,9,P,0,110,0,19:08:34.460
$P,8,P,0,105,0,19:08:34.407
$L,8,SF
$P,9,A,0,139,0,19:08:34.374
$P,15,P,0,103,0,19:08:34.532
$P,8,P,0,73,0,19:08:34.436
$L,8,SF
$L,8,PI

I'm currently using CsvHelper and followed this example of how to read multiple record types using a switch statement. I'm a bit stuck however, as I want to group the $P records depending on values contained in the $L records and then write the output to separate CSV files.

For example, the first and last $L records both contain an 8 in the second field, plus PO/PI messages (this would be the start/end of my file for all $P records containing 8 in the second field). The file output for 8.csv would look like this:

$P,8,P,0,102,0,19:08:34.463
$P,8,P,0,105,0,19:08:34.407
$P,8,P,0,73,0,19:08:34.436

In addition to grouping them together this way, I would like to prepend a number ahead of the $P record depending on the $L messages which contain SF and the number 8. There are 3 SF messages above containing SF and 8, so the final file would look something like this:

1,$P,8,P,0,102,0,19:08:34.463
1,$P,8,P,0,105,0,19:08:34.407
2,$P,8,P,0,73,0,19:08:34.436

What's the best way to accomplish this? Currently I'm adding all $P messages that contain the same ID number to a dictionary with key value pair of : List<$P Record>, and I'm not quite sure how to make the $P record groupings depend on the values of the other record.


Solution

  • Try something like this. It is easier to add lines to a record and then group the records.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    
    
    namespace ConsoleApplication184
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.txt";
            static void Main(string[] args)
            {
                int count = 0;
                string line = "";
                StreamReader reader = new StreamReader(FILENAME);
                List<Record> records = new List<Record>();
                while ((line = reader.ReadLine()) != null)
                {
                    int startComment = line.IndexOf("//");
                    if (startComment >= 0)
                    {
                        line = line.Substring(0, startComment);
                    }
                    line = line.Trim();
                    string[] splitArray = line.Split(new char[] { ',' }).ToArray();
                    Record newRecord = new Record();
                    newRecord.car = int.Parse(splitArray[1]);
                    newRecord.type = (Record.RECORD_TYPE)Enum.Parse(typeof(Record.RECORD_TYPE), splitArray[2]);
                    records.Add(newRecord);
    
                    switch (splitArray[0])
                    {
                        case "$P":
                            newRecord.message = line;
                            break;
                    }
                }
    
                var cars = records.GroupBy(x => x.car);
    
                foreach (var car in cars)
                {
                    int lap = 0;
                    int stint = 0;
    
                    foreach (Record record in car)
                    {
                        record.lap = lap;
                        record.stint = stint;
                        switch (record.type)
                        {
                            case Record.RECORD_TYPE.SF:
                                record.lap = ++lap;
                                break;
                            case Record.RECORD_TYPE.P:
                                string output = string.Join(",", new string[] { record.stint.ToString(), record.lap.ToString(), record.message });
                                Console.WriteLine(output);
                                break;
                            case Record.RECORD_TYPE.PO :
                                record.stint = ++stint;
                                break;
                        }
                    }
                }
    
                Console.ReadLine();
            }
    
        }
        public class Record
        {
            public enum RECORD_TYPE
            {
                PO,
                SF,
                P,
                PI,
                A
            }
            public RECORD_TYPE type { get; set; }
            public int stint { get; set; }
            public int lap { get; set; }
            public int car { get; set; }
            public string message { get; set; }
        }
    }