LINQ查询修改列表

时间:2012-03-09 20:20:20

标签: c# linq list

这似乎是一个难以破解的难题。我希望你的大师很容易。我想知道使用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线之后。
  3. 最终列表应如下所示:

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

2 个答案:

答案 0 :(得分:6)

如果要修改迭代的内容,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);
}

答案 1 :(得分:0)

尽管有其他警告,提供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);

如果您计划仅在几百甚至几千个条目的数据上运行此项,这可能表现得非常好,您不需要找到更有效的解决方案。重要的是你不要假设任何实现都足够快 - 只需确定它们的时间。您还应该看到输入大小加倍会影响代码的运行时间 - 然后您可以预测它将在更大和更大的输入大小上执行的效果。

我不保证上述代码经过测试或无错误。 4.0中添加了Zip,因此如果您之前使用的是框架,它将无法使用。否则,实施自己的Zip是值得的。快乐的编码。