嵌套的ForEach循环到Linq

时间:2013-02-05 11:07:09

标签: c# linq foreach linq-to-entities nested-loops

我正在尝试将下面的每个循环嵌套转换为Linq。但是我仍然无法成功。

var objAct = new List<InformaticsBenchmarkSummary>();
foreach (var item in op)
{
    foreach (var lstTp5 in lstTopFive)
    {
        if (item.UnitOfOperations.ContainsKey(lstTp5.SystemID))
        {
            var objIbm = new InformaticsBenchmarkSummary();
            objIbm.CompanyId = item.CompanyId;
            objIbm.CompanyName = item.CompanyName;
            objIbm.LocationId = item.LocationId;
            objIbm.LocationName = item.LocationName;
            objIbm.UnitOfOperations.Add(lstTp5.SystemID, 
                                        item.UnitOfOperations[lstTp5.SystemID]);
            objAct.Add(objIbm);
        }
    }
}

其中UnitOfOperations的类型为Dictionary<int,string>();
op再次List<InformaticsBenchmarkSummary>()
lstTopFiveList<int>()

我尝试过,类似这样但语法不成功

var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
let v = new InformaticsBenchmarkSummary()
{
     CompanyId = item.CompanyId,
     CompanyName = item.CompanyName,
     LocationId = item.LocationId,
     LocationName = item.LocationName
}
.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID])
select v;

嵌套循环完美运行但我认为,linq就可以提高性能。 感谢任何帮助。

4 个答案:

答案 0 :(得分:2)

在Linq查询语法中,不可能在select中使用UnitOfOperations.Add。但是你可以使用Method Chain和SelectMany方法来实现它:

var objAcu = (op.SelectMany(item => lstTopFive, (item, lstTp5) => new { item, lstTp5 })  // <- Bad readability
                .Where(t => t.item.UnitOfOperations.ContainsKey(t.lstTp5.SystemID))
                .Select(t =>
                        {
                            var objIbm = new InformaticsBenchmarkSummary
                            {
                                CompanyId = t.item.CompanyId,
                                CompanyName = t.item.CompanyName,
                                LocationId = t.item.LocationId,
                                LocationName = t.item.LocationName
                            };
                            objIbm.UnitOfOperations.Add(t.lstTp5.SystemID, t.item.UnitOfOperations[t.lstTp5.SystemID]);
                            return objIbm;
                        })).ToList();

如果属性UnitOfOperations具有公开set,则在这种情况下,您可以使用查询语法。

如何替换1 foreach?按from ... in ...

然后,要替换2 foreach,请使用2 from ... in ...

var objAct = (from item in op  // First foreach loop
              from lstTp5 in lstTopFive  // Second foreach loop
              where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
              select new InformaticsBenchmarkSummary
              {
                  CompanyId = item.CompanyId,
                  CompanyName = item.CompanyName,
                  LocationId = item.LocationId,
                  LocationName = item.LocationName,
                  UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
              }).ToList();

但我怀疑它会在这种操作中提高性能。

无论如何,我不明白你想要达到的目的。因为在输出的所有项目中,字典UnitOfOperations中只有一个且只有一个元素。这真的是你想做的吗?

更新

List<int> systemIdTop5 = lstTopFive.Select(tp5 => tp5.SystemID).ToList();
var objAct = (from item in op
              select new InformaticsBenchmarkSummary
              {
                  CompanyId = item.CompanyId,
                  CompanyName = item.CompanyName,
                  LocationId = item.LocationId,
                  LocationName = item.LocationName,
                  UnitOfOperations = systemIdTop5.Intersect(item.UnitOfOperations.Keys)
                                                 .ToDictionary(systemId => systemId, systemId => item.UnitOfOperations[systemId])
              }).ToList();

答案 1 :(得分:1)

你很接近,但你不能在LINQ查询中使用void返回方法。 (如果不是void - 返回,则v将是Add()的结果,这很可能是错误的。)

如果您想为Dictionary创建新的UnitOfOperations,则可以将其设置为与其他属性相同的方式。但是如果你不能这样做(可能是因为UnitOfOperations有一个私有的setter)或者你不想(因为UnitOfOperations被初始化为你想保留的某个值),你可以使用C#的一个鲜为人知的特性:对象初始化器中的集合初始化器:

UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }

此代码的效果与您编写的内容相同:

createdObject.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID]);

唯一的区别是它不是一个语句,它是表达式的一部分,这意味着你可以在LINQ查询中使用它。

整个查询将是:

var output = from item in op
             from lstTp5 in lstTopFive
             where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
             select new InformaticsBenchmarkSummary()
             {
                 CompanyId = item.CompanyId,
                 CompanyName = item.CompanyName,
                 LocationId = item.LocationId,
                 LocationName = item.LocationName,
                 UnitOfOperations =
                 {
                     { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] }
                 }
             };

答案 2 :(得分:1)

据我所知,你的UnitOfOperations是你遇到的困难。如果它在构造函数中初始化,您可以使用它:

            var output = from item in op
                     from lstTp5 in lstTopFive
                     where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
                     select
                         new InformaticsBenchmarkSummary()
                             {
                                 CompanyId = item.CompanyId,
                                 CompanyName = item.CompanyName,
                                 LocationId = item.LocationId,
                                 LocationName = item.LocationName,
                                 UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
                             };

结果是IEnumerable,如果您想将其作为列表,请致电output.ToList()

两个旁注:

  1. 我不相信这会更快。它仍然是一个内循环。
  2. 这可能会在结果中产生几乎重复的项目(不同的UnitOfOperations),但我想这是理想的。在最糟糕的情况下,op中的所有项目都有一个UnitOfOperations,其中包含SystemID中的所有lstTopFive,在op.Count()*lstTopFive.Count()中为我们提供了总共output个项目1}}。

答案 3 :(得分:0)

这可以帮助你:

var output = from item in op
                 join lstTp5 in lstTopFive on item.UnitOfOperations.Key equals lstTp5.SystemID
                 select new InformaticsBenchmarkSummary
                 {
                     CompanyId = item.CompanyId,
                     CompanyName = item.CompanyName,
                     LocationId = item.LocationId,
                     LocationName = item.LocationName,
                     UnitOfOperations = item.UnitOfOperations 
                 };