2008-08-23 20 views
8

¿Cuál es la mejor manera de encontrar algo en una lista? Sé que LINQ tiene algunos trucos, pero también sugerencias para C# 2.0. Permite obtener las mejores refactorizaciones para este patrón de código común.Manera más limpia de encontrar una coincidencia en una lista

Actualmente uso de código como este:

// mObjList is a List<MyObject> 
MyObject match = null; 
foreach (MyObject mo in mObjList) 
{ 
    if (Criteria(mo)) 
    { 
     match = mo; 
     break; 
    } 
} 

o

// mObjList is a List<MyObject> 
bool foundIt = false; 
foreach (MyObject mo in mObjList) 
{ 
    if (Criteria(mo)) 
    { 
     foundIt = true; 
     break; 
    } 
} 

Respuesta

14

@ Konrad: Entonces, ¿cómo se usa? Digamos que quiero hacer coincidir mo.ID con magicNumber.

En C# 2.0 se escribiría:

result = mObjList.Find(delegate(int x) { return x.ID == magicNumber; }); 

3,0 sabe lambdas:

result = mObjList.Find(x => x.ID == magicNumber); 
1

poner el código en un método y Parada temporal y un break (y se reciclan código, como un bono) :

T Find<T>(IEnumerable<T> items, Predicate<T> p) { 
    foreach (T item in items) 
     if (p(item)) 
      return item; 

    return null; 
} 

... pero, por supuesto, este método ya existe para Lists, incluso en .NET 2.0.

4

utilizando una expresión Lambda:

List<MyObject> list = new List<MyObject>(); 

// populate the list with objects.. 

return list.Find(o => o.Id == myCriteria); 
1

Evidentemente, el impacto en el rendimiento del anonimato delegados es bastante significativo.

Código de ensayo:

static void Main(string[] args) 
    { 
     for (int kk = 0; kk < 10; kk++) 
     { 
      List<int> tmp = new List<int>(); 
      for (int i = 0; i < 100; i++) 
       tmp.Add(i); 
      int sum = 0; 
      long start = DateTime.Now.Ticks; 
      for (int i = 0; i < 1000000; i++) 
       sum += tmp.Find(delegate(int x) { return x == 3; }); 
      Console.WriteLine("Anonymous delegates: " + (DateTime.Now.Ticks - start)); 


      start = DateTime.Now.Ticks; 
      sum = 0; 
      for (int i = 0; i < 1000000; i++) 
      { 
       int match = 0; 
       for (int j = 0; j < tmp.Count; j++) 
       { 
        if (tmp[j] == 3) 
        { 
         match = tmp[j]; 
         break; 
        } 
       } 
       sum += match; 
      } 
      Console.WriteLine("Classic C++ Style: " + (DateTime.Now.Ticks - start)); 
      Console.WriteLine(); 
     } 
    } 

Resultados:

Anonymous delegates: 710000 
Classic C++ Style: 340000 

Anonymous delegates: 630000 
Classic C++ Style: 320000 

Anonymous delegates: 630000 
Classic C++ Style: 330000 

Anonymous delegates: 630000 
Classic C++ Style: 320000 

Anonymous delegates: 610000 
Classic C++ Style: 340000 

Anonymous delegates: 630000 
Classic C++ Style: 330000 

Anonymous delegates: 650000 
Classic C++ Style: 330000 

Anonymous delegates: 620000 
Classic C++ Style: 330000 

Anonymous delegates: 620000 
Classic C++ Style: 340000 

Anonymous delegates: 620000 
Classic C++ Style: 400000 

En todos los casos, el uso de los delegados anónimos es de aproximadamente 100% más lento que a la inversa.

+1

No, el rendimiento alcanzado aquí no está utilizando el delegado. Sus algoritmos funcionan fundamentalmente diferente, el primer método tiene tiempo de ejecución asintótico O (n^2) mientras que el segundo tiene tiempo de ejecución O (n). Esto no tiene nada que ver con los delegados, sino con el uso de la función 'Buscar' en este contexto. –

Cuestiones relacionadas