【问题标题】:Grouping records together using multiple record types in CsvHelper在 CsvHelper 中使用多种记录类型将记录分组在一起
【发布时间】:2021-03-15 16:30:45
【问题描述】:

我有一个大型日志文件,其中包含要解析的不同记录类型。它看起来像这样:

$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

我目前正在使用 CsvHelper 并关注 this example 如何使用 switch 语句读取多种记录类型。但是我有点卡住了,因为我想根据 $L 记录中包含的值对 $P 记录进行分组,然后将输出写入单独的 CSV 文件。

例如,第一条和最后一条 $L 记录都在第二个字段中包含 8,加上 PO/PI 消息(对于所有在第二个字段中包含 8 的 $P 记录,这将是我文件的开始/结束) . 8.csv 的文件输出如下所示:

$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

除了以这种方式将它们组合在一起之外,我还想根据包含 SF 和数字 8 的 $L 消息在 $P 记录之前添加一个数字。上面有 3 条包含 SF 和 8 的 SF 消息,所以最终文件看起来像这样:

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

完成此任务的最佳方法是什么?目前,我将所有包含相同 ID 号的 $P 消息添加到键值对为:List 的字典中,我不太确定如何使 $P 记录分组取决于值其他记录。

【问题讨论】:

    标签: c# .net-core csvhelper


    【解决方案1】:

    试试这样的。将行添加到记录然​​后对记录进行分组更容易。

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

    【讨论】:

    • 谢谢,但这似乎会在每次达到 $L 时增加计数,而不检查 $L 是否包含与 $P 相同的数字(或者它是否是 SF、PO 或PI 类型)。我想我需要为这些添加检查,然后采取相应的行动?
    • 我不这么认为。你的信息太少,我无法确定你需要什么。 40 多年来,我一直在解析这样的数据,并根据自己的最佳判断提出了上述代码。
    • $P 消息是来自赛车模拟中各种汽车的遥测数据(例如:汽车编号、速度、RPM 等),$L 消息指示汽车何时进站(PO - 进入赛道),进站(PI - 离开赛道),或越过起点/终点线(SF)。我想将来自汽车的 $P 消息组合在“限制”中,该“限制”定义为该汽车的 PI 和 PO 消息之间的圈数 (SF)。例如,如果 8 号车进站 ($L,8,PO),完成 5 圈,然后进站 ($L,8,PI),我想编写一个包含这些圈的 $P 数据的文件(重复每个汽车在赛道上以及汽车的每一次进站)。
    • 现在部分工作。我看到按圈数分组的输出,但我的输出文件需要针对每个时间段(PO 和 PI 之间的圈数)。例如,在我的初始日志文件示例中,如果我添加了额外的 PI、PO 和 SF 行,并且在 PO 和 PI 之间有 8 号车的 $P,我得到 $P 的第 3 圈,但没有任何迹象表明它是新工作的一部分。
    • 感谢您,订购很棒。但是,我认为我没有正确解释我所说的限制。请参阅this annotated 输入和输出,了解我上述评论的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 1970-01-01
    相关资源
    最近更新 更多