2013-03-22 262 views
3

我對按多列排序列表有疑問。在下面的示例中,儘管我排序以顯示None, A First Description, B Second...,但列表仍按打印順序打印。按多列對C#列表排序

List<MySample> samples = new List<MySample>(); 

samples.Add(new MySample { SortOrder = 1, Data = "A First Description", Description = "A First Description" }); 
samples.Add(new MySample { SortOrder = 1, Data = "C Third Description", Description = "C Third Description" }); 
samples.Add(new MySample { SortOrder = 1, Data = "B Second Description", Description = "B Second Description" }); 
samples.Add(new MySample { SortOrder = 0, Data = "None", Description = "None" }); 
samples.OrderBy(a => a.SortOrder).ThenBy(a => a.Description).ToList(); 

foreach (var item in samples) 
{ 
    Console.WriteLine(item); 
} 

public class MySample 
{ 
    public int SortOrder { get; set; } 
    public string Description { get; set; } 
    public object Data { get; set; } 
} 

如果我更改我的代碼以執行以下操作,則會按照所需順序進行打印。

samples = samples.OrderBy(a => a.SortOrder).ThenBy(a => a.Description).ToList(); 

排序可以不分配(如上所述)嗎?

僅供參考,這個例子不是實際的代碼。我需要通過使用FrameworkElementFactory後面的代碼將此列表數據綁定到ComboBoxWPF

感謝您的幫助!

更新與我的方法:

var collectionView = CollectionViewSource.GetDefaultView(<My list to be sorted>); 
collectionView.SortDescriptions.Add(new SortDescription("SortOrder", ListSortDirection.Ascending)); 
collectionView.SortDescriptions.Add(new SortDescription("Description", ListSortDirection.Ascending)); 

上面的確在UI的伎倆。我感謝所有的快速答案。

+2

'List'提供了'排序'函數不需要賦值,但它更復雜,因爲它涉及編寫自己的比較器。 – 2013-03-22 17:21:47

+0

一個基本問題。所有的答案都非常有幫助。我不確定我在這種情況下如何選擇正確答案? – isakavis 2013-03-22 19:20:03

回答

4

原因是因爲OrderBy不轉換它所調用的對象,而是返回一個新的結果。你應該使用這樣的:

samples = samples.OrderBy(a => a.SortOrder).ThenBy(a => a.Description).ToList(); 

這是OrderBy功能的工作方式。爲什麼你需要它以另一種方式工作,特別是對於一些額外的字符。

可能通過創建你自己的擴展方法,除了創建一個新的結果,而不是創建一個新的結果,但除此之外做同樣的事情,但這不值得麻煩。


如果你需要的東西,雖然,你可以只包裹中的LINQ擴展方法,像這樣:

public static void MyOrderBy(this List<MySample> list) 
{ 
    list = list.OrderBy(a => a.SortOrder).ThenBy(a => a.Description).ToList(); 
} 

和像這樣使用它:

samples.MyOrderBy(); 

這只是一個想法,但我不知道它是否會起作用,或者它是否是個好主意。

+0

感謝您的反饋。在實際的代碼中,我無法爲列表分配orderby,因爲它是我們無法更改的對象的一部分。我在想,如果排序比較器會給我所需的功能(如肯德爾的評論)?基本目標是不要更改原始對象,而要根據UI需要對其進行排序以供顯示。不知道我是否清楚地解釋了我的約束。如果不清楚,請告訴我。 – isakavis 2013-03-22 17:34:16

+0

@isakavis:我做了一個編輯,它只是一個想法,但也許它會幫助你 – musefan 2013-03-22 17:41:42

+2

這是行不通的,因爲'list'不是'ref'參數;即,您只是在方法「MyOrderBy」內爲本地副本分配新列表。 – 2013-03-22 17:49:11

2

既然你有一個List,你可以做到這一點老派的方式:

samples.Sort((s1, s2) => { 
    int compare = s1.SortOrder.CompareTo(s2.SortOrder); 
    if (compare != 0) return compare; 
    compare = s1.Description.CompareTo(s2.Description); 
    return compare; 
}); 

但我可能會使用LINQ堅持。更容易閱讀。僅適用於特定的環路設置的順序 -

//other code above... 
samples.Add(new MySample { SortOrder = 0, Data = "None", Description = "None" }); 
foreach (var item in samples.OrderBy(a => a.SortOrder).ThenBy(a => a.Description)) 
//other code below... 

注意samples是順序不變:

+0

是的。這有一個就地排序的優點,並且不會像LINQ方法那樣創建一個新列表。 – 2013-03-22 17:55:30

1

則可以將例如改變。

如果這些都不可接受,請詳細解釋您的需求。

0

只是一種替代,「請不要這樣做,除非沒有別的適合」的路線,你可以添加新屬性進行排序的合併:

class NoReallyThisIsACodeSmell 
{ 
    public string SortPlusDescription 
    { 
      return string.Concat(SortOrder, Description); 
    } 
} 
+0

我正在走這條路線(正如你所說的,「不要這樣做」),你需要格式化SortOrder的值,所以數字總是相同的,比如'string.Concat(SortOrder。 ToString(「0000000000」),Description) - 你的值將是'0000000123ABC'和'0000000012CDE'。 – 2013-03-22 18:04:23

+1

@JoeEnos好點 - 當我的手機發布答案時,我有耐心的限制:) – JerKimball 2013-03-22 18:06:21