0

我有一个 for each 循环来获取非常耗时的数据。任何将其转换为 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);
                            }
                        }
                    }
                }
4

2 回答 2

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)

于 2013-05-30T07:51:39.847 回答
1

干得好。我已经将您的代码直接翻译成 LINQ,希望能帮助您了解我是如何转换它的。

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

还要注意group byLINQ 查询底部的使用,以确保我们只获取每个 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 和 from

您可以将 foreach 子句直接交换为 LINQ from 子句。你可以看到:

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 中唯一需要做一些不同的部分。

首先,我们按“DocumentID”对“taskInfo”进行分组。

group taskInfo by taskInfo.DocumentID into grouping

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

select grouping.First().DocumentID;

关于 Distinct 的说明

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

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

于 2013-05-30T08:51:57.010 回答