【问题标题】:Nested ForEach loop to Linq将 ForEach 循环嵌套到 Linq
【发布时间】:2023-03-17 01:05:01
【问题描述】:

我正在尝试将下面嵌套的每个循环转换为 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);
        }
    }
}

UnitOfOperationsDictionary&lt;int,string&gt;() 类型;
op 又是 List&lt;InformaticsBenchmarkSummary&gt;()
lstTopFiveList&lt;int&gt;()

我试过了,类似这样,但在语法上不成功

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 会提高性能。 感谢任何帮助。

【问题讨论】:

  • ReSharper 可以为您做到这一点。如果您不想购买,可以下载 30 天评估版。
  • 大多数情况下,LINQ 不会提高性能,它必须执行您现在正在执行的所有循环。
  • @levelnis 通常可以,但在这种特定情况下,即使是 ReSharper 也无法做到。

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


【解决方案1】:

在 Linq 查询语法中不可能在选择中使用 UnitOfOperations.Add。但是你可以使用方法链和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();

【讨论】:

  • 感谢 Cedric 的回复。是的,你的理解是对的。我正在尝试获取在 lstTopFive 中具有相应键的所有 UnitOfOperations。 UnitOfOperations 字典有很多元素,但我想选择其中的几个,但保持其他 CompanyId、LocationId 和名称不变..
  • 这不是不可能的,有一个确切的语法,看我的回答。
  • @SagarS。我已经更新了我的答案以返回一个新的 InformaticsBenchmarkSummary 列表,其中过滤了 UnitOfOperations 以仅获取 lstTopFive 中定义的 UnitOfOperation .
  • @CédricBignon 谢谢塞德里克。感谢您的帮助。
  • @SagarS。我能理解您为什么接受了 svick 的回答吗?鉴于我在 15 分钟前编写了完全相同的代码。
【解决方案2】:

据我所知,您遇到困难的是您的 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,其中包含 lstTopFive 中的所有 SystemID,从而使我们在 output 中总共有 op.Count()*lstTopFive.Count() 项目。

【讨论】:

  • 感谢您的分析。如果性能不会提高,我肯定会考虑它,因为嵌套的 foreach 比 linq 具有更高的可读性
【解决方案3】:

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

如果您想为UnitOfOperations 创建一个新的Dictionary,您可以像其他属性一样设置它。但是如果你不能这样做(可能是因为UnitOfOperations 有一个私有设置器)或者你不想这样做(因为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] }
                 }
             };

【讨论】:

  • 非常感谢。那就是我被困的地方,你给我指明了正确的方向。因为, UnitOfOperation 已经在构造函数中初始化;你的解决方案适合我
【解决方案4】:

希望对你有帮助:

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

【讨论】:

    猜你喜欢
    • 2011-06-07
    • 2017-10-26
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    相关资源
    最近更新 更多