Утилита Списка <T>.Sort () по сравнению с <T>.OrderBy Списка () для члена пользовательского контейнерного класса

Я оказался отбегающий через некоторых старые 3,5 унаследованных кода платформы и нашел некоторые точки, где существует целый набор списков и словарей, которые должны быть обновлены синхронизируемым способом. Я решил, что могу сделать этот процесс бесконечно легче и использовать и понять путем схождения их в пользовательские контейнерные классы новых пользовательских классов. Существуют некоторые точки, однако, куда я пришел к проблемам с организацией содержания этих новых контейнерных классов определенным внутренним свойством. Например, сортируя по свойству Идентификационного номера одного класса.

Поскольку контейнерные классы, прежде всего, базируются вокруг универсального Объекта списка, мой первый инстинкт должен был записать внутренние классы с IComparable и записать метод CompareTo, который сравнивает свойства. Таким образом, я могу просто звонить items.Sort() когда я хочу вызвать сортировку.

Однако я думал вместо этого об использовании items = items.OrderBy(Func) вместо этого. Таким образом, это более гибко, если я должен отсортировать по свойству. Удобочитаемость лучше также, так как свойство, используемое для сортировки, будет перечислено встроенное с вызовом вида вместо того, чтобы иметь необходимость искать код IComparable. Полная реализация чувствует инструмент для очистки в результате.

Я не забочусь о преждевременной или микро оптимизации, но мне нравится непротиворечивость. Я нахожу, что он лучше всего придерживается одного вида реализации для стольких же случаев, сколько это является соответствующим, и используйте различные реализации, где это необходимо. Действительно ли это стоит того для преобразования моего кода для использования LINQ OrderBy вместо того, чтобы использовать Список. Вид? Действительно ли это - лучшая практика, чтобы придерживаться реализации IComparable для этих пользовательских контейнеров? Есть ли какие-либо значительные механические преимущества, предлагаемые любым путем, о котором я должен взвешивать решение? Или действительно ли их функциональность конца эквивалентна до такой степени, что это просто становится предпочтением кодера?

9
задан Grace Note 16 June 2010 в 18:31
поделиться

2 ответа

Главное здесь то, что List .Sort () выполняет сортировку на месте. Если ваш список открыт для внешнего кода, он всегда будет представлять один и тот же объект для этого кода. Это важно, если список хранится в поле по коду вне класса контейнера. Если вы выполняете сортировку с помощью OrderBy () , вы будете каждый раз получать новое перечисление, заменяя предыдущие элементы . Любой ранее сохраненный список не будет отображать текущее состояние вашего класса.

Учитывая производительность, OrderBy должен будет перебирать весь список для сортировки элементов. Затем вы вызовете ToList () , чтобы создать новый список из этого перечисления, повторяя список во второй раз. Кроме того, поскольку это перечисление, List будет использовать алгоритм удвоения, увеличивая его размер до тех пор, пока в него не поместится каждый элемент. В случае большого списка это может быть довольно много выделений и копирования памяти. Я ожидал, что производительность будет намного хуже, чем у List .Sort () .

Редактировать: Небольшой тест:

internal class Program {

    private static List<int> CreateList(int size) {

        // use the same seed so that every list has the same elements
        Random random = new Random(589134554);

        List<int> list = new List<int>(size);
        for (int i = 0; i < size; ++i)
            list.Add(random.Next());
        return list;
    }

    private static void Benchmark(int size, bool output = true) {
        List<int> list1 = CreateList(size);
        List<int> list2 = CreateList(size);

        Stopwatch stopwatch = Stopwatch.StartNew();
        list1.Sort();
        stopwatch.Stop();
        double elapsedSort = stopwatch.Elapsed.TotalMilliseconds;
        if (output)
            Console.WriteLine("List({0}).Sort(): {1}ms (100%)", size, elapsedSort);

        stopwatch.Restart();
        list2.OrderBy(i => i).ToList();
        stopwatch.Stop();
        double elapsedOrderBy = stopwatch.Elapsed.TotalMilliseconds;
        if (output)
            Console.WriteLine("List({0}).OrderBy(): {1}ms ({2:.00%})", size, elapsedOrderBy, elapsedOrderBy / elapsedSort);

    }

    internal static void Main() {

        // ensure linq library is loaded and initialized
        Benchmark(1000, false);

        Benchmark(10);
        Benchmark(100);
        Benchmark(1000);
        Benchmark(10000);
        Benchmark(100000);
        Benchmark(1000000);

        Console.ReadKey();
    }
}

Вывод (нормализованный в List.Sort):

List(10).Sort(): 0,0025ms (100%)
List(10).OrderBy(): 0,0157ms (628,00%)
List(100).Sort(): 0,0068ms (100%)
List(100).OrderBy(): 0,0294ms (432,35%)
List(1000).Sort(): 0,0758ms (100%)
List(1000).OrderBy(): 0,3107ms (409,89%)
List(10000).Sort(): 0,8969ms (100%)
List(10000).OrderBy(): 4,0751ms (454,35%)
List(100000).Sort(): 10,8541ms (100%)
List(100000).OrderBy(): 50,3497ms (463,88%)
List(1000000).Sort(): 124,1001ms (100%)
List(1000000).OrderBy(): 705,0707ms (568,15%)
19
ответ дан 4 December 2019 в 09:12
поделиться

Как сказал Julien, Sort(), вероятно, будет быстрее, однако, поскольку вы упомянули лучшую читаемость и гибкость OrderBy(), вы можете достичь этого и с помощью метода Sort() (по крайней мере, если свойства, на которых вы хотите основывать сортировку, сопоставимы)

items = items.OrderBy(x => x.Name).ToList();
items.Sort((x,y) => x.Name.CompareTo(y.Name)); // If x.Name is never null
items.Sort((x,y) => String.Compare(x.Name, y.Name)); // null safe
4
ответ дан 4 December 2019 в 09:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: