22 votes

Moins verbeux de la manipulation de la première passe dans un foreach?

Je me retrouve souvent à faire la suite d'index de compteur de désordre dans une boucle foreach pour savoir si je suis sur le premier élément ou non. Est-il plus élégante façon de le faire en C#, quelque chose le long des lignes de if(this.foreach.Pass == 1) etc.?

int index = 0;
foreach (var websitePage in websitePages) {
    if(index == 0)
        classAttributePart = " class=\"first\"";
    sb.AppendLine(String.Format("<li" + classAttributePart + ">" + 
        "<a href=\"{0}\">{1}</a></li>", 
        websitePage.GetFileName(), websitePage.Title));
    index++;
}

13voto

Tomas Petricek Points 118959

Une autre approche consiste à accepter que le "laid partie" doit être mis en œuvre quelque part et de fournir une couche d'abstraction qui cache le "laid partie", de sorte que vous n'avez pas à répéter dans de multiples lieux et peuvent se concentrer sur l'algorithme spécifique. Cela peut être fait en utilisant des expressions lambda C# (ou à l'aide de C# 2.0 délégués anonymes si vous n'êtes pas pour .NET 2.0):

void ForEachWithFirst<T>(IEnumerable<T> en, 
     Action<T> firstRun, Action<T> nextRun) {
  bool first = true;
  foreach(var e in en) {
    if (first) { first = false; firstRun(e); } else nextRun(e);
  }
}

Maintenant, vous pouvez utiliser cette réutilisables méthode à mettre en œuvre un algorithme comme ceci:

ForEachWithFirst(websitePages,
  (wp => sb.AppendLine(String.Format("<li class=\"first\">" +
         "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title)))
  (wp => sb.AppendLine(String.Format("<li>" + 
         "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title))) );

Vous pouvez concevoir l'abstraction différemment selon la nature exacte de motif de répétition. La bonne chose est que, grâce à l'expression lambda - la structure de l'abstraction est complètement à vous.

11voto

Mark Byers Points 318575

Un peu moins verbeux:

string classAttributePart = " class=\"first\"";
foreach (var websitePage in websitePages)
{
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
    classAttributePart = string.Empty;
}

Si vous êtes en utilisant .NET 3.5, vous pouvez utiliser la surcharge de Sélectionner ce qui vous donne l'index et le tester. Alors vous aussi n'aurait pas besoin de le StringBuilder. Voici le code pour que:

string[] s = websitePages.Select((websitePage, i) =>
        String.Format("<li{0}><a href=\"{1}\">{2}</a></li>\n",
                      i == 0 ? " class=\"first\"" : "",
                      websitePage.GetFileName(),
                      websitePage.Title)).ToArray();

string result = string.Join("", s);

Il ressemble un peu plus verbeux, mais c'est principalement parce que je me suis cassé la très longue ligne de nombreux courts.

4voto

Joel Potter Points 12759
if (websitePages.IndexOf(websitePage) == 0)
    classAttributePart = " class=\"last\"";

Cela peut être plus élégant, mais il sera probablement moins performant puisqu'il doit vérifier l'index de chaque élément.

4voto

John Knoeller Points 20754

Cela pourrait être légèrement mieux

bool doInit = true;
foreach (var websitePage in websitePages)
{
    if (doInit)
    {
        classAttributePart = " class=\"first\"";
        doInit = false;
    }
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}

J'ai fini par faire ce genre de chose, beaucoup trop, et ça me dérange aussi.

4voto

Brian R. Bondy Points 141769

Vous pouvez utiliser un for boucle au lieu d'un foreach boucle. Dans ce cas, votre boucle, pourrait commencer c'est de l'indice à 1 et que vous pourriez faire le premier élément en dehors de la boucle si la longueur est supérieure à 0.

Au moins dans ce cas, vous n'auriez pas à faire une comparaison supplémentaire à chaque itération.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X