LINQ查询以修改列表

本文关键字:列表 修改 查询 LINQ | 更新日期: 2023-09-27 18:27:28

这似乎是一个难以破解的难题。我希望这对你们这些大师来说很容易。我想知道使用LINQ是否可以做到这一点。

这是我的清单:

ABC,1,RON,26,73
CDE,13,JON,21,18
ERROR,ERROR LINE,ERROR LINE,DEF
DEF,NOT AVAILABLE,"",JANE,32,13
GHI,23,DAWN,14,25

我需要用这个列表完成两件事:

  1. 将带有ERROR的行和下一行移动到列表底部
  2. ERROR之后的下一行(以"DEF"开头的行)必须进行修改,以便所有字段都与正确的字段对齐。但是,我仍然应该留在ERROR行之后

最后的列表应该是这样的:

ABC,1,RON,26,73
CDE,13,JON,21,18
GHI,23,DAWN,14,25
ERROR,ERROR LINE,ERROR LINE,DEF
DEF,NOT AVAILABLE,JANE,32,13

现在,我完整、详细的LINQ查询如下:

var myList = (File.ReadLines(myFile.ToString(), Encoding.GetEncoding(1250)))
    .ToList()
    .OrderBy(l => l[0].ToString())
    .Select(l => new specialclass {
        Comp = l[0].ToString(),
        Place = Convert.ToInt32(l[1].ToString()),
        Name = l[2].ToString(),
        Limit = Convert.ToInt32(l[3].ToString()),
        Limit2 = Convert.ToInt32(l[4].ToString())
    });

LINQ查询以修改列表

如果您想修改迭代内容,那么LINQ不是合适的工具。如果您需要大量使用索引器,这也是不合适的。

这是另一种应该对您有所帮助的方法:

var data = System.IO.File.ReadAllLines(@"C:'Temp'Data.csv");
var result = new List<String>();
var errors = new List<Tuple<int, String, String>>();
for (int i = 0; i < data.Length; i++)
{
    var line = data[i];
    var cols = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    if (cols[0].ToUpper() == "ERROR")
    {
        var nextLine = data.Length > i+1 ? data[i + 1].Replace("'"'"","") : String.Empty;
        var nextCols = nextLine.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
            .Where(col => !String.IsNullOrWhiteSpace(col) && !(col.Trim() == "0"));
        var errorInfo = Tuple.Create(i, line, String.Join(",", nextCols));
        errors.Add(errorInfo);
        i++;
    }
    else {
        result.Add(line);
    }
}
foreach(var error in errors)
{
    result.Add(error.Item2);
    result.Add(error.Item3);
}

尽管有其他警告,提供LINQ解决方案还是值得考虑的,即使它最终不是解决这个问题的正确方案。

我将提供一个LINQ解决方案,其中需要注意的是,一个适合生产的解决方案应该进行错误检查和参数验证,包括检查文件的格式是否正确,这很有趣,但超出了这里要求的范围,而且通常在功能上做起来有点困难。

var myList = 
    File.ReadLines(myFile.ToString(), Encoding.GetEncoding(1250))
    .Select(line => 
    {
        var split = line.Split(',');
        return new specialclass
        {
            Comp = split[0],
            Place = Convert.ToInt32(split[1]),
            Name = split[2],
            Limit = Convert.ToInt32(split[3]),
            Limit2 = Convert.ToInt32(split[4])
        };
    })
    .ToList();
var itemsAndPrevious = new specialclass [] { null }
    .Concat(myList)
    .Zip(myList, (prev,item) => new { prev, item });
var itemsWithoutError =
    itemsAndPrevious
        .Where(i => i.item.Comp != "Error" // omit error line
            && (i.prev == null || i.prev.Comp != "Error")) // omit line following error lines
        .Select(i => i.item)
        .OrderBy(i => i.Comp);
var itemsWithError = 
    itemsAndPrevious.Where(i => i.prev != null && i.prev.Comp == "Error")
    .OrderBy(i => i.item.Comp)
    .SelectMany(i => new [] { i.prev, i.item });
var desiredResult = itemsWithoutError.Concat(itemsWithError);

如果您计划仅在包含几百甚至几千个条目的数据上运行此功能,则此功能可能表现良好,不需要找到更高效的解决方案。重要的是,你不要想当然地认为任何实现都足够快——只是为了确定时间。您还应该了解加倍的输入大小如何影响代码的运行时间,然后您就可以预测在越来越大的输入大小上这将如何执行。

我不保证以上代码经过测试或没有错误。Zip是在4.0中添加的,因此如果您使用之前的框架,它将不可用。否则,实现自己的Zip是一项有价值的工作。快乐的编码。