Quelle est la meilleure façon d'itérer une liste générique fortement typée?

Quelle est la meilleure façon d'itérer à travers une liste générique fortement typée dans C#.NET et VB.NET?

15
demandé sur billmaya 2008-08-19 00:49:22

7 réponses

Pour C#:

foreach(ObjectType objectItem in objectTypeList)
{
    // ...do some stuff
}

réponse pour VB.NET from Fourmi Violette:

For Each objectItem as ObjectType in objectTypeList
    'Do some stuff '
Next
30
répondu mbillard 2010-04-21 18:07:30

avec n'importe quelle implémentation générique de IEnumerable la meilleure façon est:

//C#
foreach( var item in listVariable) {
    //do stuff
}

il y a cependant une exception importante. IEnumerable implique un overhead de Current() et MoveNext () qui est ce en quoi la boucle foreach est compilée.

Lorsque vous avez un simple tableau de structures:

//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
     int item = valueTypeArray[i];
     //do stuff
}

Est plus rapide.


mise à Jour

suite à une discussion avec @Steven Sudit (voir les commentaires) je pense mon premier conseil peut être périmé ou erroné, alors j'ai fait quelques tests:

// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();

// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
    int inLoop = item;
}
Console.WriteLine("list  foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theList[i];
}
Console.WriteLine("list  for    : " + sw.Elapsed.ToString());

// now run the same tests, but with an array
var theArray = theList.ToArray();

sw.Reset();
sw.Start();

foreach (var item in theArray)
{
    int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());

sw.Reset();
sw.Start();

// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
    int inLoop = theArray[i];
}
Console.WriteLine("array for    : " + sw.Elapsed.ToString());

Console.ReadKey();

Donc, j'ai couru ce dans la version avec toutes les optimisations:

list  foreach: 00:00:00.5137506
list  for    : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for    : 00:00:00.0954890

déboguer sans optimisations:

list  foreach: 00:00:01.1289015
list  for    : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for    : 00:00:00.4913245

il semble Donc assez cohérent, for est plus rapide que foreach et les tableaux sont plus rapides que les listes génériques.

cependant, c'est à travers 100 000 000 itérations et la différence est d'environ .4 d'une seconde entre les méthodes les plus rapides et les plus lentes. À moins que vous ne fassiez des boucles critiques de performance, ça ne vaut pas la peine de vous en faire.

20
répondu Keith 2010-04-23 14:36:23

pour VB.NET:

For Each tmpObject as ObjectType in ObjectTypeList
    'Do some stuff '
Next
4
répondu Brian G Swanson 2008-08-18 21:01:07

C#

myList<string>().ForEach(
    delegate(string name)
    {
        Console.WriteLine(name);
    });

les délégués anonymes ne sont pas actuellement mis en œuvre en VB.Net, mais à la fois C# et VB.Net devrait pouvoir faire lambdas:

C#

myList<string>().ForEach(name => Console.WriteLine(name));

VB.Net

myList(Of String)().ForEach(Function(name) Console.WriteLine(name))

comme L'a fait remarquer Grauenwolf, la VB ci-dessus ne sera pas compilée puisque la lambda ne renvoie pas de valeur. Une boucle ForEach normale comme d'autres l'ont suggéré est probablement la plus facile pour le moment, mais comme d'habitude il faut un bloc de code pour faire ce que C# peut faire dans un ligne.


voici un exemple banal de la raison pour laquelle ceci pourrait être utile: cela vous donne la possibilité de passer dans la logique de boucle d'une autre Portée que celle où existe L'IEnumerable, donc vous n'avez même pas à l'exposer si vous ne le voulez pas.

supposons que vous ayez une liste de chemins d'url relatifs que vous voulez rendre absolus:

public IEnumerable<String> Paths(Func<String> formatter) {
    List<String> paths = new List<String>()
    {
        "/about", "/contact", "/services"
    };

    return paths.ForEach(formatter);
}

alors vous pouvez appeler la fonction de cette façon:

var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);

vous donner "http://myhost.com/about", "http://myhost.com/contact" etc. Évidemment, il ya des de meilleures façons d'accomplir ceci dans cet exemple spécifique, j'essaie juste de démontrer le principe de base.

4
répondu Adam Lassek 2010-04-22 02:08:53

sans connaître la mise en œuvre interne d'une liste, je pense que généralement la meilleure façon d'itérer sur elle serait une boucle foreach. Parce que foreach utilise un IEnumerator pour parcourir la liste, c'est à la liste elle-même de déterminer comment passer d'un objet à l'autre.

si l'implémentation interne était, disons, une liste liée, alors une simple boucle serait un peu plus lente qu'une foreach.

cela Fait-il sens?

2
répondu Matt Hamilton 2008-08-18 21:06:49

Cela dépend de votre demande:

  • pour la boucle, si l'efficacité est une priorité
  • boucle foreach ou ForEach méthode, selon le communique votre intention plus clairement
2
répondu jfs 2008-08-19 02:01:14

il se peut que je manque quelque chose, mais itérer à travers une liste générique devrait être assez simple si vous utilisez mes exemples ci-dessous. La classe List < > implémente les interfaces IList et IEnumerable de sorte que vous pouvez facilement les itérer de n'importe quelle façon.

la manière la plus efficace serait d'utiliser a pour boucle:

for(int i = 0; i < genericList.Count; ++i) 
{
     // Loop body
}

Vous pouvez également choisir d'utiliser une boucle foreach:

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}
1
répondu Dan Herbert 2008-08-18 20:54:56