2008-08-23 2 views
8

Что такое лучший способ найти что-то в списке? Я знаю, что у LINQ есть интересные трюки, но давайте также получим предложения для C# 2.0. Давайте получим лучшие рефакторинги для этой общей схемы кода.Самый чистый способ найти совпадение в списке

В настоящее время я использую такой код:

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

или

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

ответ

14

@ Konrad: Как вы его используете? Предположим, я хочу сопоставить mo.ID с magicNumber.

В C# 2.0 вы бы написать:

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

3,0 знает лямбды:

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

Поместите код в методе, и вы сохраните временное и в break (и вы перерабатывают код, в качестве бонуса) :

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

    return null; 
} 

... но, конечно, этот метод уже существует для списков даже в .NET 2.0.

4

Использование лямбда-выражения:

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

// populate the list with objects.. 

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

Очевидно, что падение производительности анонимных делегаты довольно значительны.

код теста:

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(); 
     } 
    } 

Результаты:

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 

В любом случае, с использованием анонимных делегатов составляет около 100% медленнее, чем другим способом.

+1

Нет, производительность здесь не используется делегатом. Ваши алгоритмы существенно отличаются друг от друга, первый метод имеет асимптотическое время выполнения O (n^2), а во втором - время выполнения O (n). Это не имеет ничего общего с делегатами, а скорее с использованием функции «Найти» в этом контексте. – 2008-11-04 07:37:09