C# 排序列表的首选方式是什么<;T>;根据多种标准?

C# 排序列表的首选方式是什么<;T>;根据多种标准?,c#,C#,我有一个内存列表,其中包含大约100万条记录,有多列(日期、名称、值、Id等) 我的问题:对如此大的列表进行多列排序的最佳解决方案(即提供最佳性能)是什么 示例(伪代码): 原则上,有两种方法可以对通用列表进行排序: 使用Linq方法链: var orderedEnumerable = list.OrderByDescending(item => item.Property0) .ThenBy(item => item.Property1) .ThenBy(item

我有一个内存列表,其中包含大约100万条记录,有多列(日期、名称、值、Id等)

我的问题:对如此大的列表进行多列排序的最佳解决方案(即提供最佳性能)是什么

示例(伪代码):


原则上,有两种方法可以对通用列表进行排序:

  • 使用Linq方法链:

    var orderedEnumerable = list.OrderByDescending(item => item.Property0)
        .ThenBy(item => item.Property1)
        .ThenBy(item => item.Property2);
    
  • 使用自定义比较器实现
    IComparer
    。使用比较器,您可以创建一个新的有序枚举

    var orderedEnumerable = list.OrderBy(item => item, new MyComparer());
    
    或者,您可以使用
    sort()
    方法就地排序:

    list.Sort(new MyComparer());
    
尝试对不同的方法进行基准测试(提示:我希望就地
List.Sort(IComparer)
原则上运行得最快,但这完全取决于是否要枚举
Enumerable.OrderBy的整个结果)

下面是一个简单的基准测试示例:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

class Record
{
    public string Name { get; set; }

    public int Age { get; set; }

    public double Salary { get; set; }
}


class RecordComparer : IComparer<Record>
{
    public int Compare(Record x, Record y)
    {
        // Sort by Name, Age, and then Salary
        if (x.Name != y.Name) return x.Name.CompareTo(y.Name);
        if (x.Age != y.Age) return x.Age.CompareTo(y.Age);
        return x.Salary.CompareTo(y.Salary);
    }
}

class Program
{
    static Random _random = new Random();
    static List<Record> _list;

    static void Main(string[] args)
    {
        Profile("SortUsingLinqMethodChain", 50, InitList, SortUsingLinqMethodChain);
        Profile("SortUsingLinqComparer", 50, InitList, SortUsingLinqComparer);
        Profile("SortUsingListSort", 50, InitList, SortUsingListSort);
    }

    static void InitList()
    {
        _list = new List<Record>();

        for (int i = 0; i < 10000; i++)
        {
            _list.Add(new Record { Name = RandomString(12), Age = RandomAge() });
        }
    }

    static void SortUsingLinqMethodChain()
    {
        // NOTE: the `ToList` materialization may not be necessary at all
        //    This totally depends on what you want to do with the result.
        _list = _list.OrderBy(item => item.Name)
                     .ThenBy(item => item.Age)
                     .ThenBy(item => item.Salary).ToList();
    }

    static void SortUsingLinqComparer()
    {
        // NOTE: the `ToList` materialization may not be necessary at all
        //    This totally depends on what you want to do with the result.
        _list = _list.OrderBy(item => item, new RecordComparer()).ToList();
    }

    static void SortUsingListSort()
    {
        _list.Sort(new RecordComparer());
    }

    // based on http://stackoverflow.com/a/1344242/40347
    public static string RandomString(int length)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        return new string(Enumerable.Repeat(chars, length)
          .Select(s => s[_random.Next(s.Length)]).ToArray());
    }

    public static int RandomAge()
    {
        return _random.Next(100) + 1;
    }

    public static double RandomSalary()
    {
        return _random.NextDouble() * 100000;
    }

    // based on http://stackoverflow.com/a/1048708/40347
    static double Profile(string description, int iterations, Action init, Action func)
    {
        // Run at highest priority to minimize fluctuations 
        // caused by other processes/threads
        Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        // warm up 
        init();
        func();

        var watch = new Stopwatch();

        // clean up
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        for (int i = 0; i < iterations; i++)
        {
            init();
            watch.Start();
            func();
            watch.Stop();
        }

        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.Elapsed.TotalMilliseconds);
        return watch.Elapsed.TotalMilliseconds;
    }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用系统线程;
课堂记录
{
公共字符串名称{get;set;}
公共整数{get;set;}
公共双薪{get;set;}
}
类记录器比较器:IComparer
{
公共整数比较(记录x,记录y)
{
//按姓名、年龄和薪水排序
如果(x.Name!=y.Name)返回x.Name.CompareTo(y.Name);
如果(x.Age!=y.Age)返回x.Age.CompareTo(y.Age);
返回x.Salary.CompareTo(y.Salary);
}
}
班级计划
{
静态随机_Random=新随机();
静态列表_列表;
静态void Main(字符串[]参数)
{
配置文件(“SortUsingLinqMethodChain”,50,初始列表,SortUsingLinqMethodChain);
简介(“SortUsingLinqComparer”,50,初始列表,SortUsingLinqComparer);
配置文件(“SortUsingListSort”,50,InitList,SortUsingListSort);
}
静态void InitList()
{
_列表=新列表();
对于(int i=0;i<10000;i++)
{
_添加(新记录{Name=RandomString(12),Age=RandomAge()});
}
}
静态void SortUsingLinqMethodChain()
{
//注:“ToList”的具体化可能根本没有必要
//这完全取决于你想对结果做什么。
_list=\u list.OrderBy(item=>item.Name)
.ThenBy(item=>item.Age)
.ThenBy(item=>item.Salary).ToList();
}
静态void SortUsingLinqComparer()
{
//注:“ToList”的具体化可能根本没有必要
//这完全取决于你想对结果做什么。
_list=_list.OrderBy(item=>item,newrecordcomparer()).ToList();
}
静态void SortUsingListSort()
{
_排序(新的RecordComparer());
}
//基于http://stackoverflow.com/a/1344242/40347
公共静态字符串RandomString(int-length)
{
常量字符串chars=“abcdefghijklmnopqrstuvwxyz012456789”;
返回新字符串(可枚举。重复(字符,长度)
.选择(s=>s[_random.Next(s.Length)]).ToArray();
}
公共静态int随机化()
{
返回_random.Next(100)+1;
}
公共静态双随机薪酬()
{
返回_random.NextDouble()*100000;
}
//基于http://stackoverflow.com/a/1048708/40347
静态双配置文件(字符串描述、int迭代、Action init、Action func)
{
//以最高优先级运行以最小化波动
//由其他进程/线程引起
Process.GetCurrentProcess().PriorityClass=ProcessPriorityClass.High;
Thread.CurrentThread.Priority=ThreadPriority.Highest;
//热身
init();
func();
var watch=新秒表();
//清理
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
对于(int i=0;i
您对如何对
列表进行排序做了哪些研究?你发现了什么?您在实施研究中发现的解决方案时遇到了哪些问题?我考虑了sortset,但我认为这还不够满足我的需求性能数据的存储方式?它只是内存中的一个
列表吗?你是怎么弄到的?@Trườ你写的具体实现是什么?你在性能测试中发现了什么?比你的要求低了多少?@enkryptor是的,我的名单在记忆中。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

class Record
{
    public string Name { get; set; }

    public int Age { get; set; }

    public double Salary { get; set; }
}


class RecordComparer : IComparer<Record>
{
    public int Compare(Record x, Record y)
    {
        // Sort by Name, Age, and then Salary
        if (x.Name != y.Name) return x.Name.CompareTo(y.Name);
        if (x.Age != y.Age) return x.Age.CompareTo(y.Age);
        return x.Salary.CompareTo(y.Salary);
    }
}

class Program
{
    static Random _random = new Random();
    static List<Record> _list;

    static void Main(string[] args)
    {
        Profile("SortUsingLinqMethodChain", 50, InitList, SortUsingLinqMethodChain);
        Profile("SortUsingLinqComparer", 50, InitList, SortUsingLinqComparer);
        Profile("SortUsingListSort", 50, InitList, SortUsingListSort);
    }

    static void InitList()
    {
        _list = new List<Record>();

        for (int i = 0; i < 10000; i++)
        {
            _list.Add(new Record { Name = RandomString(12), Age = RandomAge() });
        }
    }

    static void SortUsingLinqMethodChain()
    {
        // NOTE: the `ToList` materialization may not be necessary at all
        //    This totally depends on what you want to do with the result.
        _list = _list.OrderBy(item => item.Name)
                     .ThenBy(item => item.Age)
                     .ThenBy(item => item.Salary).ToList();
    }

    static void SortUsingLinqComparer()
    {
        // NOTE: the `ToList` materialization may not be necessary at all
        //    This totally depends on what you want to do with the result.
        _list = _list.OrderBy(item => item, new RecordComparer()).ToList();
    }

    static void SortUsingListSort()
    {
        _list.Sort(new RecordComparer());
    }

    // based on http://stackoverflow.com/a/1344242/40347
    public static string RandomString(int length)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        return new string(Enumerable.Repeat(chars, length)
          .Select(s => s[_random.Next(s.Length)]).ToArray());
    }

    public static int RandomAge()
    {
        return _random.Next(100) + 1;
    }

    public static double RandomSalary()
    {
        return _random.NextDouble() * 100000;
    }

    // based on http://stackoverflow.com/a/1048708/40347
    static double Profile(string description, int iterations, Action init, Action func)
    {
        // Run at highest priority to minimize fluctuations 
        // caused by other processes/threads
        Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        // warm up 
        init();
        func();

        var watch = new Stopwatch();

        // clean up
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        for (int i = 0; i < iterations; i++)
        {
            init();
            watch.Start();
            func();
            watch.Stop();
        }

        Console.Write(description);
        Console.WriteLine(" Time Elapsed {0} ms", watch.Elapsed.TotalMilliseconds);
        return watch.Elapsed.TotalMilliseconds;
    }
}