2009-11-16 6 views
1

Comment effectuer cela sans itération, avec LINQ?Obtenir le paramètre de la dernière itération avec LINQ

string[] flatSource = {"region1", "subregion1", 
         "region2", "sub1", "sub2", 
         "region3", "sub1", "sub2"}; 

string previousRegion = ""; 
foreach (var item in flatSource) 
{ 
    if (SomeRegionDictionary.Contains(item)) 
     previousRegion = item; //This is what I can't figure out 
    else 
     yield return new SubregionWithRegion{Region = previousRegion, SubRegion = item}; 
} 

Répondre

3

Votre solution actuelle est correcte; LINQ n'est pas le choix idéal pour de telles requêtes avec état. Voici une solution purement LINQ; ce n'est pas idéal car il est un peu cryptique et a une complexité quadratique, mais est fonctionnellement équivalent:

return flatSource.Select((item, index) => 
        new SubregionWithRegion 
        { 
         Region = flatSource.Take(index + 1) 
              .LastOrDefault(SomeRegionDictionary.ContainsKey) ?? "", 
         SubRegion = item 
        }) 
        .Where(srwr => !SomeRegionDictionary.ContainsKey(srwr.SubRegion)); 

La nature stateful de la boucle est gérée avec les Take + LastOrDefault requêtes, et la else délicate état est géré par la dernière clause Where.

2

Il semble que je n'ai pas lu la question avec suffisamment d'attention. Donc l'extension ci-dessous pourrait être utile, mais pas à cette question.

public static class IEnumerableOfTExtensions 
{ 
    public static T Before<T>(this IEnumerable<T> source, Func<T, bool> condition) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     if (condition == null) 
      throw new ArgumentNullException("condition"); 

     using (var e = source.GetEnumerator()) 
     { 
      var first = true; 
      var before = default(T); 

      while (e.MoveNext()) 
      { 
       if (condition(e.Current)) 
       { 
        if (first) 
         throw new ArgumentOutOfRangeException("condition", "The first element corresponds to the condition."); 

        return before; 
       } 

       first = false; 
       before = e.Current; 
      } 
     } 

     throw new ArgumentOutOfRangeException("condition", "No element corresponds to the condition."); 
    } 
} 
+0

Comment fonctionne la finale requête venir n'importe où près de résoudre la question initiale de l'OP? – Ani

+0

@Ani: Vous avez raison. Je n'ai juste pas lu la question assez attentivement. Alors je laisse ma réponse ici, mais la tienne semble résoudre le problème concret. – Oliver

1

Vous pouvez le faire dans une déclaration avec Zip 4.0 Net:

return 
flatSource.Where(i=>SomeRegionDictionary.Contains(i)).Zip(arr.Skip(1), 
    (first, second) => new SubregionWithRegion{Region = first, SubRegion = second}); 

Si vous ne disposez pas 4.0 Net, vous pouvez utiliser cette implémentation: Zip Me Up

Questions connexes