对列表包装类进行排序

时间:2012-03-15 13:39:19

标签: c# sorting random

我有一个包装List的类,并添加了处理比率的功能。它需要在不同的时间以两种方式分类;按顺序位置,按比例的数量。

以下是我目前用于按顺序排序的方法,我想将其用作两个相关问题的基础:

  1. 有更多的执行方式吗?
  2. 如何使用IComparer执行此操作?
  3. 传递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);
            }
        }
    

3 个答案:

答案 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)

为什么不应该使用三种不同的方法而不是一种?