У мене клас, як це:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
Насправді це набагато більше, але це відтворює проблему (дивності).
Я хочу отримати суму Value
, де дійсний екземпляр. Поки що я знайшов два рішення для цього.
Перший - це:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
Однак другий:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Я хочу отримати найбільш ефективний метод. Я, по-перше, думав, що другий буде ефективнішим. Тоді теоретична частина мене почала йти: "Ну, один - O (n + m + m), другий - O (n + n). Перший повинен працювати краще, ніж більше інвалідів, а другий повинен працювати краще з меншою ». Я думав, що вони будуть виступати однаково. EDIT: І тоді @Martin вказував, що Де і Вибір поєднані, тому насправді це повинно бути O (m + n). Однак якщо подивитися нижче, здається, це не пов’язано.
Тому я поставив це на тест.
(Це 100+ рядків, тому я подумав, що краще опублікувати це як історію.)
Результати були ... цікаві.
З дотриманням 0% відхилення:
Ваги знаходяться в користь Select
і Where
, приблизно ~ 30 балів.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
З 2% відхиленням:
Це те саме, за винятком того, що для деяких вони були в межах 2%. Я б сказав, що це мінімальна помилка. Select
і Where
тепер маєте лише 20-кратне відрив.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
З 5% -ним відхиленням:
Це я б сказав, що це моя максимальна помилка. Це робить його трохи краще для Select
, але не набагато.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
З дотриманням 10% відхилення:
Це вихід з моєї помилки, але мене все ще цікавить результат. Тому що це дає Select
і Where
двадцять очок, які він мав на деякий час.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
З дозволом на 25%:
Це шлях, шлях з мого краю помилки, але я все ще зацікавлений в результаті, тому що Select
і до Where
сих пір (майже) тримати їх 20 очок. Здається, що це перевершує це на декількох кількох, і саме це дає йому перевагу.
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Зараз я здогадуюсь, що 20-бальний відрив прийшов із середини, де вони обоє зобов'язані обійти одну й ту ж виставу. Я міг би спробувати ввійти, але це було б цілком завантажене інформацією. Графік був би кращим, я думаю.
Отже, це я і зробив.
Це показує, що Select
лінія тримається стійкою (очікуваною) і що Select + Where
лінія піднімається вгору (очікується). Однак, що спантеличує мене, чому він не зустрінеться з Select
на 50 або вище: насправді я очікував раніше , ніж 50, в якості додаткового переписувач мав бути створений для Select
іWhere
. Я маю на увазі, це показує 20-кратну перевагу, але це не пояснює, чому. Це, мабуть, головний момент мого питання.
Чому він поводиться так? Чи варто їй довіряти? Якщо ні, чи слід використовувати інший чи цей?
Як в коментарях згадував @KingKong, ви також можете використовувати Sum
перевантаження, яке лямбда. Тож два мої варіанти тепер змінені на це:
Перший:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Друге:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Я зроблю його трохи коротше, але:
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where: 60
Sum: 41
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 8
Where: 55
Sum: 38
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 21
Where: 49
Sum: 31
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 39
Where: 41
Sum: 21
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where: 16
Sum: 0
Двадцятибальний відрив все ще існує, це означає, що це не має відношення до Where
таSelect
комбінації вказували @Marcin в коментарях.
Дякуємо, що прочитали мою стінку тексту! Крім того, якщо вам цікаво, ось модифікована версія, що записує CSV, який приймає Excel.
Where
+ Select
не викликає двох відокремлених ітерацій над колекцією вхідних даних. LINQ to Objects оптимізує його в одну ітерацію. Детальніше читайте на моєму щоденнику
mc.Value
.