C# 对列表包装器类进行排序
我有一个类,它包装了一个列表,并添加了处理比率的功能。它需要在不同的时间以两种方式进行分类;按顺序排列,按比例大小排列 以下是我目前使用的按顺序位置排序的方法,我想以此作为两个相关问题的基础:C# 对列表包装器类进行排序,c#,sorting,random,C#,Sorting,Random,我有一个类,它包装了一个列表,并添加了处理比率的功能。它需要在不同的时间以两种方式进行分类;按顺序排列,按比例大小排列 以下是我目前使用的按顺序位置排序的方法,我想以此作为两个相关问题的基础: 有没有更好的方法 我将如何使用IComparer进行此操作 传入IComparer的主要动机是允许不同的实现随机地洗牌列表。但是在代码中我看不到任何解析。我正在寻找一些示例代码和它的用法,这样我就可以对它了如指掌了 干杯, 贝里尔 // ///维护适合在分配中使用的比率列表 ///所有项目的总和正好等于一
贝里尔
//
///维护适合在分配中使用的比率列表
///所有项目的总和正好等于一(100%)。任何个人都不能这样做
///小于零或大于一。
///
公共类比率:IList
{
私有只读IList_items=new List();
私有随机数;
公共无效命令(索引排序命令){
IList ordered=null;
开关(订购)
{
case IndexOrdering.FirstToLast:
打破
案例IndexOrdering.LastToFirst:
有序=this.Reverse().ToList();
打破
案例索引排序。随机:
如果(_rnd==null)_rnd=new Random();
有序=可枚举。范围(0,计数)
.OrderBy(x=>\u rnd.Next())
.选择(索引=>此[索引])
.ToList();
打破
违约:
抛出新ArgumentOutOfRangeException(“排序”);
}
if(ordered==null)返回;
清除();
foreach(已订购的var ra){
添加(ra);
}
}
您的方法的性能不是最佳的,因为您没有进行就地排序。相反,您将每个项目复制两次。首先在调用ToList
中,然后在调用Add
中
IComparer
接口与执行就地排序的方法结合使用。因此,这应该是一种方法
您首先需要将
\u项的类型更改为列表
对于您想要支持的每个排序,您需要创建一个实现IComparer
的新类。如果这些类不用于其他地方,您可以将它们作为私有类放在RatioBag
中
然后,您的Order
方法将如下所示:
public void Order(IndexOrdering ordering)
{
switch (ordering)
{
case IndexOrdering.FirstToLast:
_items.Sort(new AscendingComparer());
break;
case IndexOrdering.LastToFirst:
_items.Sort(new DescendingComparer());
break;
case IndexOrdering.Random:
_items.Sort(new RandomComparer());
break;
default:
throw new ArgumentOutOfRangeException("ordering");
}
}
但是,我建议删除索引排序
枚举,并为每种排序类型提供一种排序方法。代码会更干净。您的方法的性能不是最佳的,因为您没有进行就地排序。相反,您要将每个项复制两次。首先在调用ToList
然后在对的调用中添加
IComparer
接口与执行就地排序的方法结合使用。因此,这应该是一种方法
您首先需要将\u项的类型更改为列表
对于您想要支持的每个排序,您需要创建一个实现IComparer
的新类。如果这些类不用于其他地方,您可以将它们作为私有类放在RatioBag
中
然后,您的Order
方法将如下所示:
public void Order(IndexOrdering ordering)
{
switch (ordering)
{
case IndexOrdering.FirstToLast:
_items.Sort(new AscendingComparer());
break;
case IndexOrdering.LastToFirst:
_items.Sort(new DescendingComparer());
break;
case IndexOrdering.Random:
_items.Sort(new RandomComparer());
break;
default:
throw new ArgumentOutOfRangeException("ordering");
}
}
但是,我建议删除索引排序
枚举,并为每种排序类型提供一种排序方法。代码会更干净。为什么不应该使用三种不同的方法而不是一种呢?为什么不应该使用三种不同的方法而不是一种呢?马上,我看不出你能做多少除了尽可能避免调用此方法外,它的速度更快,因为排序和重建列表本身就很慢:-)。一种可能的选择是使用SortedSet,这将使集合保持排序顺序,从而帮助您避免每次更改集合时都要诉诸的相关成本呃,我想当您更改排序策略时(尽管我敢打赌SortedSet实现人员在编写代码时一定会考虑到这一点)
我想这并不能真正回答您的问题,但您是否可以将Func传递给Order()方法(并放弃IndexOrdering枚举),然后将该Func直接传递给OrderBy()呢方法?这将允许您在不接触该类的情况下表达各种疯狂的排序方法,并且您可以从该类中删除任何不必要的状态包袱(如_rnd,如果它不在其他任何地方使用的话)
比如:
public class RatioBag : IList<RatioAssociation>
{
private readonly IList<RatioAssociation> _items = new List<RatioAssociation>();
public void Order(Func<RatioAssociation, int> func) {
var ordered = _items.OrderBy(func);
_items.Clear();
((List<RatioAssociation>)_items).AddRange(ordered);
}
}
IComparer解决方案也可以实现类似的解决方案
希望这有帮助
Nate一开始,除了尽可能避免调用此方法外,我真的看不到你能做多少事情来加快它,因为排序和重建列表本身就很慢:-)。一个可能的选择是使用SortedSet,它将保持集合的排序顺序,从而帮助你避免与排序相关的成本每次更改集合时进行ESORT。虽然我认为在更改排序策略时没有多大帮助(尽管我敢打赌SortedSet实现人员在编写代码时一定考虑过这一点)
我想这并不能真正回答您的问题,但您是否可以将Func传递给Order()方法(并放弃IndexOrdering枚举),然后将该Func直接传递给OrderBy()呢方法?这将允许您在不接触此类的情况下表达各种疯狂的排序方法,并且您可以删除
var myCollection = new RatioBag();
myCollection.Order(item => item.PropertyX);
myCollection.Order(item => item.PropertyY);
var r = new Random();
myCollection.Order(item => r.Next());