2012-03-09 86 views
-1

这似乎是一个棘手的问题。我希望你的专家很容易。我想知道这是否可以使用LINQ。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. 移动与错误的行和下一行到列表
  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()) 
    }); 
+3

这些数据是如何真正安排的?显示一些代码。这对我来说看起来不太像。 – Yuck 2012-03-09 20:22:34

+3

当你用linq枚举它的时候,你不能修改某些东西,所以这个问题看起来是无效的。此外,它很难理解“我的名单”是什么。每行都是列表中的对象?或者你是在谈论通过Linq运行更新查询到Sql? – Will 2012-03-09 20:23:56

+0

我正在阅读具有双空格作为分隔符的旧文本文件。为了简单起见,我使用了逗号。现在,我的完整,详细的LINQ查询如下所示:var myList =(File.ReadLines(myFile.ToString(),Encoding.GetEncoding(1250)))。ToList() \t .OrderBy(l => l [0 ]。的ToString()) \t。选择(L =>新specialclass \t { \t \t小样= 1 [0]的ToString(), \t \t地方= Convert.ToInt32(L [1]的ToString()), \t \t名称= 1 [2]的ToString(), \t \t极限= Convert.ToInt32(L [3]的ToString()), \t \t LIMIT2 = Convert.ToInt32(升[4]的ToString() ) \t}); – 2012-03-09 20:34:58

回答

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); 
} 
+0

好吧,这并不是所有你需要的,因为它不会修改错误行(这不是完全清楚如何),但也许你现在在正确的轨道:) – 2012-03-09 21:07:31

+0

有没有一种简单的方法来弄清楚出来吗?但是你肯定指出了我的正确方向。 – 2012-03-09 21:19:04

+0

@inquisitive_one:然后明确定义应该删除什么以及为什么。我看到''“'但这只是一个例子吗?在您的示例数据中,还有一个字段比其他行更多,但情况总是如此(有时甚至更多非法字段的内容不同)? – 2012-03-09 21:24:10

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

如果你打算从几百甚至几千个条目仅与任何地方的数据运行此,可以执行不够好,你不会需要找到更有效的解决方案。重要的是,你不要假定任何实现都会足够快 - 只需确定时间即可。您还应该看看输入大小加倍会如何影响代码的运行时间 - 然后您可以预测这种情况在更大和更大的输入大小上的表现。

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