Знайти () проти Де ().


161

Я часто бачу людей, які використовують Where.FirstOrDefault()пошук і захоплюють перший елемент. Чому б просто не використовувати Find()? Чи є перевага перед іншим? Я не міг сказати різниці.

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}

45
FWIW, list.FirstOrDefault(x => x == "item3");є більш стислим, ніж використання обох .Whereта .FirstOrDefault.
Кірк Волл

@Kirk, я думаю, моє наступне питання було б, чому вони взагалі додали цю знахідку. Це хороша порада. Єдине, про що я можу подумати - це те, що FirstOrDefault може повернути інше значення за замовчуванням, крім null. Інакше це просто здається безглуздим доповненням.
KingOfHypocrites

8
Findдо LINQ. (вона була доступна в .NET 2.0, і ви не можете використовувати лямбда. Ви змушені були використовувати звичайні методи або анонімні методи)
Kirk Woll

Відповіді:


205

Де FindметодIEnumerable<T> ? (Риторичне питання.)

WhereІ FirstOrDefaultметоди застосовні в відношенні декількох видів послідовностей, в тому числі List<T>, T[], Collection<T>і т.д. Будь-послідовності , яка реалізує IEnumerable<T>можуть використовувати ці методи. Findдоступний лише для List<T>. Способи, які, як правило, більш застосовні, потім є більш повторними та мають більший вплив.

Я думаю, моє наступне питання було б, чому вони взагалі додали цю знахідку. Це хороша порада. Єдине, про що я можу подумати - це те, що FirstOrDefault може повернути інше значення за замовчуванням, крім null. Інакше це просто здається безглуздим доповненням

Findна List<T>попередніх інші методи. List<T>був доданий з generics в .NET 2.0 і Findвходив до API цього класу. Whereі FirstOrDefaultбули додані як методи розширення для IEnumerable<T>Linq, яка є пізнішою версією .NET. Я не можу з впевненістю сказати, що якби Linq існував з версією 2.0, яка Findніколи не була б додана, але, мабуть, це стосується багатьох інших функцій, що з'явилися в більш ранніх версіях .NET, які були зроблені застарілими або надлишковими пізнішими версіями.


85
Просто для доповнення: Не потрібно телефонувати Де і Перший, або Перший або Стандартний: або Перший, або ПершийДо замовчування дозволяє вказати пошуковий предикат, що робить виклик Де непотрібним
Робсон Роша

4
Але Where(condition).FirstOrDefault()оптимізується принаймні так само добре, а іноді і краще, ніж FirstOrDefault(condition)поодинці. Ми завжди використовуємо Where()для отримання покращеної продуктивності, коли є.
Suncat2000

7
@ Suncat2000 наведіть приклад, будь ласка
Костянтин Салаватов

2
@ Suncat2000 Ви використовуєте Linq завдяки своїй виразній силі і хочете написати декларативний код. Вам не слід перейматися такими мікро вдосконаленнями, які також можуть змінитись у майбутніх впровадженнях. Крім того, не оптимізуйте занадто рано
Петро Фальковський,

50

Я тільки що дізнався сьогодні, роблячи деякі тести в списку 80K об'єктів і виявили , що Find()може бути до 1000% швидше , ніж використання Whereз FirstOrDefault(). Я цього не знав, поки не тестував таймер до і після всіх. Іноді це був той самий час, інакше швидше.


6
Ви спробували це з Where AND FirstOrDefault? Якщо ви, можливо, спробуйте це лише з FirstOrDefault і подивіться, чи все ще Find ().
MVCKarl

5
Це звучить так, ніби ви не матеріалізували результат за допомогою .ToList()або .ToArray()фактично виконати запит.
Ендрю Мортон

4
Це тому, що Findвикористовує первинні ключі (отже, індекси), тоді Whereяк це звичайний запит sql
percebus

4
Як і в EF6, Find і FirstOrDefault генерують абсолютно однакові оператори SQL. Ви можете бачити SQL у консольному додатку, виконуючи контекст.Database.Log = Console.Write; Приклад розміщення - це використання в пам'яті "Знайти" проти списку рядків, а не проти БД з первинними ключами. Можливо, переклад висловлюваного пункту Find - який унеможливлює розбір лямбда-виразів, є причиною поліпшення продуктивності в цьому випадку. У відношенні бази даних я сумніваюся, що ви помітите різницю в ситуаціях з RL ... Мені також цікаво, чи тестували її, використовуючи
функцію

2
Ну, це поліпшення продуктивності полягає в тому, що знайдіть () перевірку в кеші об’єкта, перш ніж потрапляти в БД, тоді як куди () завжди йти БД, щоб отримати об’єкт
Gaurav

35

Існує дуже важлива відмінність, якщо джерелом даних є Entity Framework: Findзнайде суб'єкти у "доданому" стані, які ще не зберігаються, але Whereне стануть. Це за дизайном.



1

крім відповіді Ентоні Where()відвідайте всі записи, а потім поверніть результатFind() не потрібно проходити всі записи, якщо предикат збігається з даним предикатом.

так що скажіть, у вас є список тестів, що мають властивості idта nameвластивості.

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

Дасть результат 2, і лише 2 відвідування знайдуть потрібні, щоб дати результат, але якщо ви користуєтесьWhere().FirstOrDefault() ми відвідаємо всі записи, і тоді ми отримаємо результати.

Отже, коли ви знаєте, що хочете лише перший результат із записів у колекції, тоді Find()буде більш підходящимWhere().FirtorDefault();


4
але якщо ви використовуєте Where (). FirstOrDefault (), ми відвідаємо всі записи, і тоді ми отримаємо результати. Ні. FirstOrDefault"роздує" ланцюжок і перестане перераховувати все. Я використовую термін "bubble-up" для відсутності кращого вираження, тому що насправді кожен селектор / предикат буде переведений на наступний, тому останній метод у ланцюжку фактично виконує роботу першим.
Silvermind

1

Нічого собі, я просто дивлюсь підручник EF від MicrosofToolbox сьогодні на Youtube. Він сказав про використання Find () та FirstOrDefault (умова) у запиті, а Find () здійснить пошук даних, які ви щось виконали на цьому об'єкті (додайте чи відредагуйте або видаліть, але ще не збережено в базі даних), тим часом FirstOrDefault буде лише шукайте те, що вже збережено


-1

Find()- це чисельний еквівалент IE FirstOrDefault(). Ви не повинні зв'язувати обидва .Where () з .FirstOrDefault()тим, що він .Where()проходить через весь масив, а потім повторить цей список, щоб знайти перший елемент. Ви економите неймовірну кількість часу, вкладаючи свій FirstOrDefault()метод пошуку предиката .

Також я рекомендую вам ознайомитись із пов’язаним запитанням до цієї теми, щоб дізнатися більше про кращі показники використання .Find()в конкретних сценаріях Performance of Find () vs. FirstOrDefault ()


Це дублікат відповіді вище вашої. Також дивіться коментар Silvermind до цієї відповіді.
carlin.scott
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.