将每个循环的嵌套转换为LINQ

时间:2013-05-30 07:42:16

标签: asp.net linq

我有一个for循环来获取非常耗时的数据。有人建议将其转换为linq。提前谢谢。

iListReport = obj.GetClosedReports();
string sRepType ="";
foreach (ReportStatisticsInfo item in reportStatistic)
                {
                    sRepType = item.ReportName.Trim();
                    IList<string> lastClosedReport = new List<string>();
                    foreach (TaskListInfo taskInfo in iListReport)
                    {
                        string reportName = taskInfo.DocumentName.Trim();
                        if (string.Compare(sRepType, reportName, true) == 0)
                        {
                            if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close) && !lastClosedReport.Contains(taskInfo.DocumentID))
                            {
                                iClosedreportCount += 1;
                                lastClosedReport.Add(taskInfo.DocumentID);
                            }
                        }
                    }
                }

2 个答案:

答案 0 :(得分:1)

使用LINQ,您将获得一个带有重复项的IEnumerable<string>

from item in reportStatistic
from taskInfo in iiListReport
where (string.Compare(item.ReportName.Trim(), taskInfo.DocumentName.Trim(), true) == 0)
   && taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
select taskInfo.DocumentID

然后您可以Distinct().GroupBy(d => d.taskInfo)

答案 1 :(得分:1)

你走了。我已经将您的代码完全翻译成LINQ,希望能帮助您了解我是如何转换它的。

请注意使用let关键字,它允许您声明范围变量(允许您执行一次修剪,然后在多个位置使用结果)。

另请注意在LINQ查询底部使用group by以确保我们只接受每个documentID的第一次出现。

IList iListReport = obj.GetClosedReports();

var query = from item in reportStatistic
            let sRepType = item.ReportName.Trim()
            from taskInfo in iListReport
            let reportName = taskInfo.DocumentName.Trim()
            where string.Compare(sRepType, reportName, true) == 0
               && taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
            //here's how we make sure we don't get the same documentID twice
            //we group by the id and then take the first
            group taskInfo by taskInfo.DocumentID into grouping
            select grouping.First().DocumentID;

var lastClosedReport = query.ToList();

iClosedreportCount = lastClosedReport.Count;

如何将foreach循环转换为LINQ

以下是您的代码与LINQ版本的一些比较,以帮助您,如果您有时需要再次进行转换。希望这将有助于那些必须将foreach循环转换为LINQ的其他人。

1。 foreach和来自

您可以为LINQ from子句执行foreach子句的直接交换。你可以看到这个:

foreach (ReportStatisticsInfo item in reportStatistic)

已成为:

from item in reportStatistic

2)变量声明和let关键字

在foreach中声明变量时,可以将它们换成LINQ let语句。你可以看到这个声明:

sRepType = item.ReportName.Trim();

已成为:

let sRepType = item.ReportName.Trim()

3)if语句和where子句

你的if语句可以在where子句中。您可以看到以下两个if语句:

if (string.Compare(sRepType, reportName, true) == 0)

if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)

已经成为这个where子句

where string.Compare(sRepType, reportName, true) == 0
   && taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)

4)使用group by删除重复项。

到目前为止,这一切都非常简单,因为一切都是直接交换。最棘手的部分是您可以防止重复项出现在结果列表中的代码。

if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close) 
 && !lastClosedReport.Contains(taskInfo.DocumentID))
{
    iClosedreportCount += 1;
    lastClosedReport.Add(taskInfo.DocumentID);
}

这很棘手,因为它是LINQ中我们必须做的唯一不同的部分。

首先,我们将'taskInfo'分组为'DocumentID'。

group taskInfo by taskInfo.DocumentID into grouping

然后我们从每个分组中获取第一个taskInfo并获取它的ID。

select grouping.First().DocumentID;

关于Distinct的说明

很多人尝试使用Distinct来摆脱重复。当我们使用原始类型时,这很好,但是当你使用一组对象时,这可能会失败。当您使用对象时,Distinct将对两个对象进行参考比较。这将无法匹配不同实例但碰巧具有相同ID的对象。

如果您需要根据对象中的特定属性删除重复项,那么最好的方法是使用group by。