【问题标题】:C# - Lambda vs nested loopsC# - Lambda 与嵌套循环
【发布时间】:2010-12-14 17:43:23
【问题描述】:

是否可以将以下转换为更简单、更易读的 linq 或 lambda 表达式?

Dictionary<int, int> selectedProgramTierCombo = new Dictionary<int,int>();
foreach (int mainTierID in doc.TierID)
{
    foreach (PriceProgram priceProgram in doc.CommitmentProgram.PricingPrograms)
    {
        foreach (ProgramTier progTier in priceProgram.Tiers)
        {
            if (progTier.TierID == mainTierID )
            {
                selectedProgramTierCombo.Add(priceProgram.ProgramID, progTier.TierID);
            }
        }
    }
}

本质上 doc.TierID 是客户端当前所在的 TierID 的数组 (int[])。 doc 对象还包含一个 CommitmentProgram 对象,其中包含 PriceProgram 列表。所以,我要做的就是获取每个 TierID 的 PriceProgram.ProgramID。

PriceProgram 和 TierID 的关系是每个 PriceProgram 都有一个层级列表(ProgramTier 对象),而 ProgramTier 对象包含我们已经拥有的对应的 TierID。

如果我的解释没有意义,请告诉我,我会尝试详细说明。

编辑

乔恩, 当我尝试编译您所建议的内容时,我收到 The name 'priceProgram' does not exist in the current context 错误:

Dictionary<int, int> selectedProgramTierCombo = 
    (from mainTierID in doc.TierID 
     from priceProgram in doc.CommitmentProgram.PricingPrograms 
     **join progTier in priceProgram.Tiers on mainTierID equals progTier.TierID**
     select new { priceProgram.ProgramID, progTier.TierID }) 
    .ToDictionary(x => x.ProgramID, x => x.TierID);

【问题讨论】:

  • 使用泛型类型 'System.Collections.Generic.List' 需要 '1' 类型参数。
  • 我已经根据 Jon 的初始回答提供了更新的代码。
  • 我已经编辑了我的答案以使用另一个 from 子句而不是 join... 虽然听起来你根本不需要那个位,真的。

标签: c# linq loops lambda nested-loops


【解决方案1】:

当然,这很容易 - 但我必须更改您的 selectedProgramTierCombo 变量的类型,否则它将无法编译:

编辑:糟糕,鉴于层级取决于 priceProgram,我认为您需要另一个嵌套的 from 子句:

Dictionary<int, int> selectedProgramTierCombo =
    (from mainTierID in doc.TierID
     from priceProgram in doc.CommitmentProgram.PricingPrograms
     from progTier in priceProgram.Tiers
     where mainTierID == progTier.TierID
     select new { priceProgram.ProgramID, progTier.TierID })
    .ToDictionary(x => x.ProgramID, x => x.TierID);

至少,这就是我认为你想要的。如果你能澄清你真正想要的而不是List&lt;int, int&gt;(这是无效的),我们可以提供进一步的帮助。

说实话,我完全不清楚你为什么使用progTier - 你知道progTier.TierIDmainTierID 相同,除此之外你没有使用它......

【讨论】:

  • 也许他的意思是(或需要)List&lt;Tuple&lt;int,int&gt;&gt;,假设x.ProgramID 不是这个集合的唯一标识符?但是,它不会大大改变答案。
  • @Anthony:可能。很难说:(
  • 在您发表评论之前,我正在考虑通过加入来解决此问题。有人提到我从未使用过的 SelectMany(),这不是一个可行的解决方案吗?此外,我通常不会为转换而烦恼,只需将整个东西打入一个 var 中,特别是如果结构永远不会离开功能块。这纯粹是风格问题,但可能对海报有用。
  • @Eugarps,(a) Jon 的代码是SelectMany 的查询表达式语法版本。如果他要使用流利的语法重写它,那将涉及那种方法。 (b) 这里没有强制转换,他只是明确地声明了他的声明,而不是使用 var 的推断,大概是为了明确说明 OP 的集合类型无效,而正确的集合类型完全不同。
  • 其实 Jon,你明白了,我的意思是 Dictionary 不是 List。另外,您对 progTier 与 mainTierID 的看法是对的……它们是相同的,所以我必须使用 progTier。非常感谢您帮助我!
【解决方案2】:

乔恩的回答是正确的想法,只需要重新排列才能编译。这里有两个选项。

var dict = (from mainTierID in doc.TierID
            join f in
                (from priceProgram in doc.CommitmentProgram.PricingPrograms
                    from progTier in priceProgram.Tiers
                    select new { priceProgram.ProgramID, progTier.TierID })
                on mainTierID equals f.TierID
            select f).ToDictionary(f => f.ProgramID, f => f.TierID);


var dict2 = (from priceProgram in doc.CommitmentProgram.PricingPrograms
                from progTier in priceProgram.Tiers
                join mainTierID in doc.TierID on progTier.TierID equals mainTierID
                select new { priceProgram.ProgramID, progTier.TierID })
            .ToDictionary(x => x.ProgramID, x => x.TierID);

【讨论】:

  • 谢谢安东尼。第一个变体确实有助于澄清代码中发生的事情 =)
【解决方案3】:

Single 让我很不爽,但我必须满足要求。

Dictionary<int, int> selectedProgramTierCombo =
(
  from priceProgram in doc.CommitmentProgram.PricingPrograms
  let tierId =
  (
    from progTier in priceProgram.Tiers
    where doc.TierID.Any(mainTierID => mainTierID == progTier.TierID)
    select progTier.TierID
  ).Single()
  select new
  {
    ProgramID = priceProgram.ProgramID,
    TierID = tierID
  }
).ToDictionary(x => x.ProgramID, x => x.TierID);

这是我会更舒服的:

ILookup<int, int> selectedProgramTierCombo =
(
  from priceProgram in doc.CommitmentProgram.PricingPrograms
  from progTier in priceProgram.Tiers
  where doc.TierID.Any(mainTierID => mainTierID == progTier.TierID)
  select new
  {
    ProgramID = priceProgram.ProgramID,
    TierID = progTier.TierID
  }
).ToLookup(x => x.ProgramID, x => x.TierID);

【讨论】:

  • 谢谢大卫。您使用 ILookup 而不是 Dictionary 是否有特定原因?如果是这样,我想知道为什么。
  • 由于 doc.TierID 中可能有多个项目,并且 priceProgram.Tiers 中可能有多个匹配层...给定定价程序可能具有多个主要层(至少在技术意义)。 ILookup 允许我为一个键设置多个值。
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
相关资源
最近更新 更多