C# Sortable collection which allows duplicate keys

前端 未结 16 2114
旧巷少年郎
旧巷少年郎 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:58

    You can safely use List<> . The List has a Sort method , an overload of which accepts IComparer. You can create your own sorter class as . Here's an example :

    private List<Curve> Curves;
    this.Curves.Sort(new CurveSorter());
    
    public class CurveSorter : IComparer<Curve>
    {
        public int Compare(Curve c1, Curve c2)
        {
            return c2.CreationTime.CompareTo(c1.CreationTime);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 10:58

    Create a class and query the list:

    Public Class SortingAlgorithm
    {
        public int ID {get; set;}
        public string name {get; set;}
        public string address1 {get; set;}
        public string city {get; set;}
        public string state {get; set;}
        public int age {get; set;}
    }
    
    //declare a sorting algorithm list
    List<SortingAlgorithm> sortAlg = new List<SortingAlgorithm>();
    
    //Add multiple values to the list
    sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});
    sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});
    sortAlg.Add( new SortingAlgorithm() {ID = ID, name = name, address1 = address1, city = city, state = state, age = age});
    
    //query and order by the list
      var sortedlist = (from s in sortAlg
                        select new { s.ID, s.name, s.address1, s.city, s.state, s.age })
                                                         .OrderBy(r => r.ID)
                                                         .ThenBy(r=> r.name)
                                                         .ThenBy(r=> r.city)
                                                         .ThenBy(r=>r.state)
                                                         .ThenBy(r=>r.age);
    
    0 讨论(0)
  • 2020-11-28 10:59

    Here's my take on this. Be aware, here might be dragons, C# still still quite new for me.

    • Duplicate keys are allowed, values are stored in a list
    • I used it as a sorted queue, hence the names and methods

    Usage:

    SortedQueue<MyClass> queue = new SortedQueue<MyClass>();
    // new list on key "0" is created and item added
    queue.Enqueue(0, first);
    // new list on key "1" is created and item added
    queue.Enqueue(1, second);
    // items is added into list on key "0"
    queue.Enqueue(0, third);
    // takes the first item from list with smallest key
    MyClass myClass = queue.Dequeue();
    
    class SortedQueue<T> {
      public int Count;
      public SortedList<int, List<T>> Queue;
    
      public SortedQueue() {
        Count = 0;
        Queue = new SortedList<int, List<T>>();
      }
    
      public void Enqueue(int key, T value) {
        List<T> values;
        if (!Queue.TryGetValue(key, out values)){
          values = new List<T>();
          Queue.Add(key, values);
          Count += 1;
        }
        values.Add(value);
      }
    
      public T Dequeue() {
        if (Queue.Count > 0) {
          List<T> smallest = Queue.Values[0];
          if (smallest.Count > 0) {
            T item = smallest[0];
            smallest.Remove(item);
            return item;
          } else {
            Queue.RemoveAt(0);
            Count -= 1;
            return Dequeue();
          }
        }
        return default(T);
      }
    }
    
    0 讨论(0)
  • 2020-11-28 11:01

    The trick is to augment your object with a unique key. See the following test which passes. I want to keep my points sorted by their X value. Just using a naked Point2D in my comparison function will cause points with the same X value to be eliminated. So I wrap the Point2D in a tagging class called Indexed.

    [Fact]
    public void ShouldBeAbleToUseCustomComparatorWithSortedSet()
    {
        // Create comparer that compares on X value but when X
        // X values are uses the index
        var comparer = new 
            System.Linq.Comparer<Indexed<Point2D>>(( p0, p1 ) =>
            {
                var r = p0.Value.X.CompareTo(p1.Value.X);
                return r == 0 ? p0.Index.CompareTo(p1.Index) : r;
            });
    
        // Sort points according to X
        var set = new SortedSet<Indexed<Point2D>>(comparer);
    
        int i=0;
    
        // Create a helper function to wrap each point in a unique index
        Action<Point2D> index = p =>
        {
            var ip = Indexed.Create(i++, p);
            set.Add(ip);
        };
    
        index(new Point2D(9,10));
        index(new Point2D(1,25));
        index(new Point2D(11,-10));
        index(new Point2D(2,99));
        index(new Point2D(5,55));
        index(new Point2D(5,23));
        index(new Point2D(11,11));
        index(new Point2D(21,12));
        index(new Point2D(-1,76));
        index(new Point2D(16,21));
        set.Count.Should()
           .Be(10);
        var xs = set.Select(p=>p.Value.X).ToList();
        xs.Should()
          .BeInAscendingOrder();
        xs.ShouldBeEquivalentTo(new[]{-1,1,2,5,5,9,11,11,16,21});
    
    }
    

    Utilities to make this work are

    A comparer that takes a lambda

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

    A tagging struct

    public struct Indexed<T>
    {
        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<T> Create<T>(int indexed, T value)
        {
            return new Indexed<T>(indexed, value);
        }
    }
    
    0 讨论(0)
提交回复
热议问题