簡體   English   中英

LINQ條件聚合基於下一個元素的值

[英]LINQ conditional aggregation based on next elements' values

什么是這個pesudo代碼的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解決方案來解決這個問題。 在那兒?

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

正確枚舉序列意味着沒有項目知道其他項目,這顯然不適用於您的情況。 使用for循環,這樣你就可以按順序干凈地遍歷字符串。

在嘗試了for()解決方案之后,我嘗試了一個LINQ解決方案並提出了下面的解決方案。 對於我相當小的(10K行)文件,它足夠快,我不關心效率,我發現它比for()解決方案的等效更可讀。

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

可以這樣做:

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

我作弊並讓Resharper為我生成這個。 這很接近 - 但它在頂部留下了一個空白行。

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

只是為了我的好奇心。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM