2010-12-14 74 views
2

Est-il possible de convertir à la suite en une expression linq ou lambda plus lisible?C# - Lambda vs boucles imbriquées

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

Essentiellement doc.TierID est un un réseau (int []) de ce client TierIDs est actuellement. L'objet doc contient également un objet CommitmentProgram qui contient une liste de PriceProgram. Donc, tout ce que j'essaie de faire est d'obtenir le PriceProgram.ProgramID pour chaque TierID.

La relation entre PriceProgram et TierID est que chaque PriceProgram a une liste de niveaux (Objet ProgramTier) et ProgramTier oject contient le TierID correspondant que nous avons déjà. Faites-moi savoir si mon explication n'a pas de sens et je vais essayer d'élaborer.

Modifier

Jon, Je reçois Le nom « priceProgram » n'existe pas dans le contexte actuel erreur lorsque je tente de compiler ce que vous avez suggéré:

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); 
+0

Utilisation du type générique 'System.Collections.Generic.List ' exige '1' arguments de type. – ja72

+0

J'ai fourni le code mis à jour basé sur la réponse initiale de Jon. –

+0

J'ai édité ma réponse pour utiliser une autre clause 'from' au lieu de' join' ... bien qu'il semble que vous n'ayez pas du tout besoin de ce bit, vraiment. –

Répondre

4

Absolument , c'est très facile - mais je vais devoir changer le type de votre variable selectedProgramTierCombo, sinon elle ne compilera pas:

EDIT: Oops, étant donné que les niveaux dépend de priceProgram, vous avez besoin d'une autre clause from imbriquée, je pense:

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

Au moins, c'est ce que je pense vous voulez. Si vous pouviez clarifier ce que vous voulez vraiment au lieu de List<int, int> (ce qui n'est pas valide), nous pouvons vous aider davantage.

Pour être honnête, ce n'est pas clair pour moi pourquoi vous utilisez progTier du tout - vous savez que progTier.TierID est le même que mainTierID, et vous ne l'utilisez pas à part ça ...

+0

Peut-être qu'il voulait dire (ou a besoin) 'Liste >', en supposant que 'x.ProgramID' n'était pas un identifiant unique pour les besoins de cette collection? Cependant, cela ne changerait pas beaucoup la réponse. –

+0

@Anthony: Peut-être. C'est difficile à dire :( –

+0

Je pensais aborder cette question avec une jointure avant votre commentaire Quelqu'un a mentionné SelectMany(), que je n'ai jamais utilisé, n'est-ce pas une solution viable?De plus, je ne m'occupe pas habituellement du lancer, je donne juste un coup de pied dans un var, surtout si les structures ne quittent jamais le bloc fonctionnel. Ceci est purement une question de style, mais peut être utile à l'affiche. – Sprague

2

Jon la réponse est la bonne idée, il suffit de la réorganiser pour la compiler. Voici deux options.

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); 
+0

Merci Anthony. La première variation a vraiment aidé à clarifier ce qui se passe dans le code =) – Robert

1

Le genre unique de me tracasse, mais je dois aller avec ce qui est demandé.

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

C'est ce que je serais plus à l'aise avec:

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); 
+0

Merci David. Y a-t-il une raison spécifique pour laquelle vous utilisez ILookup au lieu du dictionnaire? Si oui, j'aimerais savoir pourquoi. – Robert

+0

Puisqu'il peut y avoir plus d'un élément dans doc.TierID et qu'il peut y avoir plusieurs niveaux correspondants dans priceProgram.Tiers ... un programme de tarification donné peut avoir plusieurs niveaux principaux (au moins dans un sens technique). ILookup me permet d'avoir plusieurs valeurs pour une clé. –

+0

Donne un sens. Je vous remercie! – Robert