C# Sortable collection which allows duplicate keys

前端 未结 16 2124
旧巷少年郎
旧巷少年郎 2020-11-28 10:06

I am writing a program to set a sequence in which various objects will appear in report. The sequence is the Y position (cell) on Excel spreadsheet.

A demo part of co

16条回答
  •  情深已故
    2020-11-28 10:40

    This collection class will maintain duplicates and insert sort order for the duplicate. The trick is to tag the items with a unique value as they are inserted to maintain a stable sort order. Then we wrap it all up in an ICollection interface.

    public class SuperSortedSet : ICollection
    {
        private readonly SortedSet> _Container;
        private int _Index = 0;
        private IComparer _Comparer;
    
        public SuperSortedSet(IComparer comparer)
        {
            _Comparer = comparer;
            var c2 = new System.Linq.Comparer>((p0, p1) =>
            {
                var r = _Comparer.Compare(p0.Value, p1.Value);
                if (r == 0)
                {
                    if (p0.Index == -1
                        || p1.Index == -1)
                        return 0;
    
                    return p0.Index.CompareTo(p1.Index);
    
                }
                else return r;
            });
            _Container = new SortedSet>(c2);
        } 
    
        public IEnumerator GetEnumerator() { return _Container.Select(p => p.Value).GetEnumerator(); }
    
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    
        public void Add(TValue item) { _Container.Add(Indexed.Create(_Index++, item)); }
    
        public void Clear() { _Container.Clear();}
    
        public bool Contains(TValue item) { return _Container.Contains(Indexed.Create(-1,item)); }
    
        public void CopyTo(TValue[] array, int arrayIndex)
        {
            foreach (var value in this)
            {
                if (arrayIndex >= array.Length)
                {
                    throw new ArgumentException("Not enough space in array");
                }
                array[arrayIndex] = value;
                arrayIndex++;
            }
        }
    
        public bool Remove(TValue item) { return _Container.Remove(Indexed.Create(-1, item)); }
    
        public int Count {
            get { return _Container.Count; }
        }
        public bool IsReadOnly {
            get { return false; }
        }
    }
    

    a test class

    [Fact]
    public void ShouldWorkWithSuperSortedSet()
    {
        // Sort points according to X
        var set = new SuperSortedSet
            (new System.Linq.Comparer((p0, p1) => p0.X.CompareTo(p1.X)));
    
        set.Add(new Point2D(9,10));
        set.Add(new Point2D(1,25));
        set.Add(new Point2D(11,-10));
        set.Add(new Point2D(2,99));
        set.Add(new Point2D(5,55));
        set.Add(new Point2D(5,23));
        set.Add(new Point2D(11,11));
        set.Add(new Point2D(21,12));
        set.Add(new Point2D(-1,76));
        set.Add(new Point2D(16,21));
    
        var xs = set.Select(p=>p.X).ToList();
        xs.Should().BeInAscendingOrder();
        xs.Count.Should()
           .Be(10);
        xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,5,9,11,11,16,21});
    
        set.Remove(new Point2D(5,55));
        xs = set.Select(p=>p.X).ToList();
        xs.Count.Should()
           .Be(9);
        xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,9,11,11,16,21});
    
        set.Remove(new Point2D(5,23));
        xs = set.Select(p=>p.X).ToList();
        xs.Count.Should()
           .Be(8);
        xs.ShouldBeEquivalentTo(new[]{-1,1,2,9,11,11,16,21});
    
        set.Contains(new Point2D(11, 11))
           .Should()
           .BeTrue();
    
        set.Contains(new Point2D(-1, 76))
            .Should().BeTrue();
    
        // Note that the custom compartor function ignores the Y value
        set.Contains(new Point2D(-1, 66))
            .Should().BeTrue();
    
        set.Contains(new Point2D(27, 66))
            .Should().BeFalse();
    
    }
    

    The tagging struct

    public struct Indexed
    {
        public int Index { get; private set; }
        public T Value { get; private set; }
        public Indexed(int index, T value) : this()
        {
            Index = index;
            Value = value;
        }
    
        public override string ToString()
        {
            return "(Indexed: " + Index + ", " + Value.ToString () + " )";
        }
    }
    
    public class Indexed
    {
        public static Indexed Create(int indexed, T value)
        {
            return new Indexed(indexed, value);
        }
    }
    

    The lambda comparer helper

    public class Comparer : IComparer
    {
        private readonly Func _comparer;
    
        public Comparer(Func comparer)
        {
            if (comparer == null)
                throw new ArgumentNullException("comparer");
            _comparer = comparer;
        }
    
        public int Compare(T x, T y)
        {
            return _comparer(x, y);
        }
    }
    

提交回复
热议问题