Рассмотрим следующий простой код с LINQ OrderBy
и ThenBy
:
static void Main()
{
var arr1 = new[] { "Alpha", "Bravo", "Charlie", };
var coStr = Comparer<string>.Create((x, y) =>
{
Console.WriteLine($"Strings: {x} versus {y}");
return string.CompareOrdinal(x, y);
});
arr1.OrderBy(x => x, coStr).ToList();
Console.WriteLine("--");
var arr2 = new[]
{
new { P = "Alpha", Q = 7, },
new { P = "Bravo", Q = 9, },
new { P = "Charlie", Q = 13, },
};
var coInt = Comparer<int>.Create((x, y) =>
{
Console.WriteLine($"Ints: {x} versus {y}");
return x.CompareTo(y);
});
arr2.OrderBy(x => x.P, coStr).ThenBy(x => x.Q, coInt).ToList();
}
Это просто использует некоторые компараторы, которые выводят на консоль то, что они сравнивают.
На моем оборудовании и версии Framework (.NET 4.6.2) это вывод:
Strings: Bravo versus Alpha Strings: Bravo versus Bravo Strings: Bravo versus Charlie Strings: Bravo versus Bravo -- Strings: Bravo versus Alpha Strings: Bravo versus Bravo Ints: 9 versus 9 Strings: Bravo versus Charlie Strings: Bravo versus Bravo Ints: 9 versus 9
Мой вопрос: Зачем им сравнивать элемент из запроса с самим собой?
В первом случае перед разделителем --
делают четыре сравнения. Два из них сравнивают запись с самой собой («Strings: Bravo vs Bravo»). Почему?
Во втором случае никогда не должно возникать необходимости прибегать к сравнению Q
свойств (целых чисел); поскольку в значениях P
нет дубликатов (относительно порядкового сравнения), поэтому никогда не требуется разрыва связей из ThenBy
. Тем не менее мы дважды видим «Ints: 9 vs 9». Зачем использовать компаратор ThenBy
с одинаковыми аргументами?
Примечание. Любой компаратор должен возвращать 0
при сравнении чего-либо с самим собой. Итак, если алгоритм просто не хочет проверить, правильно ли мы реализовали компаратор (что он все равно никогда не сможет сделать полностью), что происходит?
Имейте в виду: в элементах, выданных запросами в моих примерах, нет дубликатов.
Я видел ту же проблему с другим примером с большим количеством записей, полученных из запроса. Выше я просто привел небольшой пример. Это происходит и с четным числом полученных элементов.
OrderBy
должна начаться отслеживание того, какой элемент он поместил, чтобы знать, что это то же самое. Это может создать дополнительные накладные расходы для сравнительно незначительного повышения производительности, посколькуOrderBy
обычно используется для больших наборов данных (поэтому минимизируется частота проверки одинаковых элементов). - person Flater   schedule 29.08.2017EnumerableSorter<TElement>
и отладьте то, что происходит. Я предполагаю, что границы (i
иj
) в конечном итоге будут указывать на ту же запись карты, что иx
. И избежать этого было бы больше накладных расходов, чем редкие сравнения элементов с самими собой. - person René Vogt   schedule 29.08.2017currentItem
thisItemInTheList
, прежде чем сравнивать их, что для больших наборов данных может создать больше работы, чем на самом деле. решает. Это также создало бы дополнительное различие в логике для типов значений и ссылочных типов, что усложняет ситуацию. - person Flater   schedule 29.08.2017List<>.Sort
иArray.Sort<>
отличается от алгоритмаOrderBy
. И первый был изменен и улучшен, так как другой поток был активен. - person Jeppe Stig Nielsen   schedule 29.08.2017