我有一个包装List的类,并添加了处理比率的功能。它需要在不同的时间以两种方式分类;按顺序位置,按比例的数量。
以下是我目前用于按顺序排序的方法,我想将其用作两个相关问题的基础:
传递IComparer的主要动机是允许不同的实现随机混乱列表。 This post seems to address the same issue但我在代码中没有任何解析,我可以看到。我正在寻找一些示例代码和它的用法,所以我可以绕过它。
干杯,
Berryl
/// <summary>
/// Maintains a list of ratios suitable for use in an allocation when the
/// sum of all items is exactly equal to one (100%). No individual it may
/// be less than zero or greater than one.
/// </summary>
public class RatioBag : IList<RatioAssociation>
{
private readonly IList<RatioAssociation> _items = new List<RatioAssociation>();
private Random _rnd;
public void Order(IndexOrdering ordering) {
IList<RatioAssociation> ordered = null;
switch (ordering)
{
case IndexOrdering.FirstToLast:
break;
case IndexOrdering.LastToFirst:
ordered = this.Reverse().ToList();
break;
case IndexOrdering.Random:
if (_rnd == null) _rnd = new Random();
ordered = Enumerable.Range(0, Count)
.OrderBy(x => _rnd.Next())
.Select(index => this[index])
.ToList();
break;
default:
throw new ArgumentOutOfRangeException("ordering");
}
if (ordered == null) return;
Clear();
foreach (var ra in ordered) {
Add(ra);
}
}
答案 0 :(得分:2)
您的方法的表现并非最佳,因为您没有进行现场排序。相反,您要复制每个项目两次。首先打电话给ToList
,然后打电话给Add
。
IComparer
界面与 就地排序的List.Sort
方法结合使用。所以这应该是要走的路。
您首先需要将_items
的类型更改为List<RatioAssociation>
。
对于您要支持的每个订单,您需要创建一个实现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");
}
}
但是,我建议删除IndexOrdering
枚举,并为每个订购类型提供一种排序方法。代码会更清晰。
答案 1 :(得分:1)
手边,除了避免尽可能多地调用这个方法之外,我并没有真正看到你能做得更快,因为排序和重建列表本来就很慢:-)。一种可能的选择是使用SortedSet,它将按照排序顺序保持集合,从而帮助您避免每次更改集合时与求助相关的成本。虽然我认为当你改变排序策略时(虽然我敢打赌SortedSet实现者在编写代码时给出了一些想法)但没有多大帮助。
我认为这并没有真正回答你的问题,但是你可以改为传递一个Func&lt; ...&gt;而不是传递IComparer。到你的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);
}
}
然后,称之为:
var myCollection = new RatioBag();
myCollection.Order(item => item.PropertyX);
myCollection.Order(item => item.PropertyY);
var r = new Random();
myCollection.Order(item => r.Next());
IComparer解决方案也将实现类似的解决方案。
希望这有帮助。
内特
答案 2 :(得分:0)
为什么不应该使用三种不同的方法而不是一种?