c# - valores - recorrer list of t vb net
¿Cuál es la mejor manera de iterar a través de una Lista genérica<T> fuertemente tipada? (7)
Me puede estar perdiendo algo, pero iterar a través de una lista genérica debería ser bastante simple si utiliza mis ejemplos a continuación. La clase List <> implementa las interfaces IList e IEnumerable para que pueda iterar fácilmente a través de ellas básicamente de la forma que desee.
La forma más eficiente sería usar un ciclo for:
for(int i = 0; i < genericList.Count; ++i)
{
// Loop body
}
También puede optar por utilizar un bucle foreach:
foreach(<insertTypeHere> o in genericList)
{
// Loop body
}
¿Cuál es la mejor manera de iterar a través de una lista genérica fuertemente tipada en C # .NET y VB.NET?
Para VB.NET:
For Each tmpObject as ObjectType in ObjectTypeList
''Do some stuff ''
Next
Sin conocer la implementación interna de una lista, creo que, en general, la mejor manera de iterar sería un ciclo foreach. Dado que foreach usa un IEnumerator para recorrer la lista, depende de la propia lista determinar cómo moverse de un objeto a otro.
Si la implementación interna fuera, por ejemplo, una lista enlazada, entonces un bucle simple sería bastante más lento que un foreach.
¿Tiene sentido?
Depende de su aplicación:
- para bucle, si la eficiencia es una prioridad
- ciclo foreach o método ForEach, lo que comunica su intención más claramente
Para C #:
foreach(ObjectType objectItem in objectTypeList)
{
// ...do some stuff
}
Respuesta para VB.NET de Purple Ant :
For Each objectItem as ObjectType in objectTypeList
''Do some stuff ''
Next
DO#
myList<string>().ForEach(
delegate(string name)
{
Console.WriteLine(name);
});
Los delegados anónimos no se implementan actualmente en VB.Net, pero tanto C # como VB.Net deberían poder hacer lambdas:
DO#
myList<string>().ForEach(name => Console.WriteLine(name));
VB.Net
myList(Of String)().ForEach(Function(name) Console.WriteLine(name))
Como señaló Grauenwolf, el VB anterior no compilará dado que el lambda no devuelve un valor. Un bucle ForEach normal, como otros lo han sugerido, es probablemente el más fácil por ahora, pero como es habitual, se necesita un bloque de código para hacer lo que C # puede hacer en una línea.
Aquí hay un ejemplo trillado de por qué esto podría ser útil: esto le da la capacidad de pasar la lógica de bucle desde otro ámbito distinto de donde existe el IEnumerable, por lo que ni siquiera tiene que exponerlo si no lo desea.
Supongamos que tiene una lista de rutas de URL relativas que quiere que sean absolutas:
public IEnumerable<String> Paths(Func<String> formatter) {
List<String> paths = new List<String>()
{
"/about", "/contact", "/services"
};
return paths.ForEach(formatter);
}
Entonces puedes llamar a la función de esta manera:
var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);
Te doy "http://myhost.com/about", "http://myhost.com/contact"
etc. Obviamente hay mejores formas de lograr esto en este ejemplo específico, solo estoy tratando de demostrar el principio básico .
Con cualquier implementación genérica de IEnumerable, la mejor manera es:
//C#
foreach( var item in listVariable) {
//do stuff
}
Sin embargo, hay una excepción importante. IEnumerable implica una sobrecarga de Current () y MoveNext () que es en lo que se compila realmente el bucle foreach.
Cuando tienes una matriz simple de estructuras:
//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
int item = valueTypeArray[i];
//do stuff
}
Es mas rapido
Actualizar
Tras una discusión con @Steven Sudit (ver comentarios), creo que mi consejo original puede estar desactualizado o equivocado, así que realicé algunas pruebas:
// 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();
Entonces, ejecuté esto en versión con todas las optimizaciones:
list foreach: 00:00:00.5137506
list for : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for : 00:00:00.0954890
Y luego depurar sin optimizaciones:
list foreach: 00:00:01.1289015
list for : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for : 00:00:00.4913245
Por lo tanto, parece bastante consistente, for
es más rápido que foreach
y las matrices son más rápidas que las listas genéricas.
Sin embargo, esto es a través de 100.000,000 iteraciones y la diferencia es aproximadamente .4 de segundo entre los métodos más rápidos y más lentos. A menos que esté realizando ciclos críticos de rendimiento masivo, no vale la pena preocuparse.