2012-03-29 102 views
4

這個pesudo-code的LINQ等價物是什麼:「給定一個字符串列表,對於每個不包含製表符的字符串,將它連接起來(用管道分隔符)到前一個字符串的末尾,並返回結果序列「?基於下一個元素值的LINQ條件聚合

更多信息:

我有一個製表符分隔文本文件List<string>代表行。每行中的最後一個字段總是一個多行文本字段,並且該文件是由錯誤處理系統生成的,該系統錯誤地處理了嵌入換行符的字段。所以,我最終像這樣的列表:

1235 \t This is Record 1 
7897 \t This is Record 2 
8977 \t This is Record 3 
continued on the next line 
and still continued more 
8375 \t This is Record 4 

我想通過連接所有孤兒行(無標籤字符線)到上一行的末尾凝聚這個名單。就像這樣:

1235 \t This is Record 1 
7897 \t This is Record 2 
8977 \t This is Record 3|continued on the next line|and still continued more 
8375 \t This is Record 4 

for()迴路解決,這將是很容易,但我想提高我的LINQ的技能,我想知道是否有一個合理有效LINQ的解決這個問題。在那兒?

+3

說實話,這不是我會建議使用LINQ的,儘管我確信有辦法這樣做。這與它的設計不符。 – Servy 2012-03-29 23:53:42

回答

3

這不是一個應該用LINQ解決的問題。 LINQ是爲枚舉而設計的,而這最好通過迭代來解決。

正確枚舉序列意味着沒有項目知道其他項目,這顯然不適用於您的案例。使用for循環,以便您可以按順序逐個清理字符串。

+0

thx爲您的答案 - 有沒有一些超載的聚合體做什麼OP後? – BKSpurgeon 2017-02-03 04:14:18

0

可以做這樣的事情:

string result = records.Aggregate("", (current, s) => current + (s.Contains("\t") ? "\n" + s : "|" + s)); 

我被騙了,並得到ReSharper的生成這對我來說。這很接近 - 它在頂部留下了一個空行。

但是,正如你所看到的,這是不太可讀的。我意識到你正在尋找一個學習練習,但我會採取一個很好的可讀foreach循環在這一天。

0

只是爲了我的好奇心。

var originalList = new List<string> 
{ 
    "1235 \t This is Record 1", 
    "7897 \t This is Record 2", 
    "8977 \t This is Record 3", 
    "continued on the next line", 
    "and still continued more", 
    "8375 \t This is Record 4" 
}; 

var resultList = new List<string>(); 

resultList.Add(originalList.Aggregate((workingSentence, next) 
    => { 
      if (next.Contains("\t")) 
      { 
       resultList.Add(workingSentence);  
       return next; 
      } 
      else 
      { 
       workingSentence += "|" + next; 
       return workingSentence; 
      } 
    })); 

resultList應該包含你想要的。

請注意,這不是一個最佳解決方案。行workingSentence += "|" + next;可能會根據您的數據模式創建大量臨時對象。

最佳解決方案可能涉及到保持多個索引變量在字符串之前,並在下一個字符串包含製表符時將它們連接起來,而不是如上所示逐個連接。但是,由於邊界檢查和保留多個索引變量,它會比上面的更復雜:)。

更新:以下解決方案不會創建用於連接的臨時字符串對象。

var resultList = new List<string>(); 
var tempList = new List<string>(); 

tempList.Add(originalList.Aggregate((cur, next) 
    => { 
      tempList.Add(cur); 
      if (next.Contains("\t")) 
      { 
       resultList.Add(string.Join("|", tempList)); 
       tempList.Clear();  
      } 
      return next; 
    })); 

resultList.Add(string.Join("|", tempList)); 

以下是使用for循環的解決方案。

var resultList = new List<string>(); 
var temp = new List<string>(); 
for(int i = 0, j = 1; j < originalList.Count; i++, j++) 
{ 
    temp.Add(originalList[i]); 
    if (j != originalList.Count - 1) 
    { 
     if (originalList[j].Contains("\t")) 
     { 
      resultList.Add(string.Join("|", temp)); 
      temp.Clear(); 
     } 
    } 
    else // when originalList[j] is the last item 
    { 
     if (originalList[j].Contains("\t")) 
     { 
      resultList.Add(string.Join("|", temp)); 
      resultList.Add(originalList[j]); 
     } 
     else 
     { 
      temp.Add(originalList[j]); 
      resultList.Add(string.Join("|", temp)); 
     } 
    } 
} 
0

嘗試一個for()解決方案之後,我嘗試了LINQ溶液,用下面的一個上來。對於我相當小的(10K行)文件,速度足夠快,我不關心效率,並且我發現它比等效的解決方案更具可讀性。

var lines = new List<string>  
{  
    "1235 \t This is Record 1",  
    "7897 \t This is Record 2",  
    "8977 \t This is Record 3",  
    "continued on the next line",  
    "and still continued more",  
    "8375 \t This is Record 4"  
}; 
var fixedLines = lines 
     .Select((s, i) => new 
      { 
       Line = s, 
       Orphans = lines.Skip(i + 1).TakeWhile(s2 => !s2.Contains('\t')) 
      }) 
     .Where(s => s.Line.Contains('\t')) 
     .Select(s => string.Join("|", (new string[] { s.Line }).Concat(s.Orphans).ToArray())) 
相關問題