2016-12-07 26 views
-3

我有一個內存列表,包含大約100萬條記錄(多個列)(日期,名稱,值,Id,.....)按多個標準排序列表<T>的首選方式是什麼?

我的問題:什麼是最佳解決方案(即提供最佳性能)用多列來排序這麼大的列表?

例(僞代碼):

list.orderbyDesc(name).thenBy(Name).thenBy(Value) 
+0

你如何排序'List'做什麼研究?你發現了什麼?你有什麼問題執行你在研究中找到的解決方案? – Servy

+0

我想分揀,但我認爲這是不夠的,我需要的表現 –

+0

數據如何存儲?它只是一個內存中的List?你如何得到它? – enkryptor

回答

1

原則上有兩種方式來排序您的泛型列表:

  • 使用LINQ的方法鏈:

    var orderedEnumerable = list.OrderByDescending(item => item.Property0) 
        .ThenBy(item => item.Property1) 
        .ThenBy(item => item.Property2); 
    
  • 使用實現IComparer<T>的自定義比較器。通過比較器,你可以創建一個新的有序枚舉

    var orderedEnumerable = list.OrderBy(item => item, new MyComparer()); 
    

    ,或者您可以使用Sort()方法就地排序:

    list.Sort(new MyComparer()); 
    

嘗試標杆不同的方法(提示:我d原則上希望原地運行最快的List<T>.Sort(IComparer<T>),但這一切取決於您是否要列舉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 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
     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; 
    } 
} 
相關問題