2013-03-22 274 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