C# Sortable collection which allows duplicate keys

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

    This is how I solved the problem. It's meant to be thread-safe though you can simply remove the locks if you don't need that. Also note arbitrary Insert at an index is not supported because that could violate the sort condition.

    public class ConcurrentOrderedList : ICollection
    {
        private object _lock = new object();
        private SortedDictionary> _internalLists;
        Func _getSortValue;
        
        public ConcurrentOrderedList(Func getSortValue)
        {
            _getSortValue = getSortValue;
            _internalLists = new SortedDictionary>();            
        }
    
        public int Count { get; private set; }
    
        public bool IsReadOnly => false;
    
        public void Add(Titem item)
        {
            lock (_lock)
            {
                List values;
                Tsort sortVal = _getSortValue(item);
                if (!_internalLists.TryGetValue(sortVal, out values))
                {
                    values = new List();
                    _internalLists.Add(sortVal, values);
                }
                values.Add(item);
                Count++;
            }            
        }
    
        public bool Remove(Titem item)
        {
            lock (_lock)
            {
                List values;
                Tsort sortVal = _getSortValue(item);
                if (!_internalLists.TryGetValue(sortVal, out values))
                    return false;
    
                var removed = values.Remove(item);
                if (removed)
                    Count--;
                return removed;
            }
        }
    
        public void Clear()
        {
            lock (_lock)
            {
                _internalLists.Clear();
            }
        }
    
        public bool Contains(Titem item)
        {
            lock (_lock)
            {
                List values;
                Tsort sortVal = _getSortValue(item);
                if (!_internalLists.TryGetValue(sortVal, out values))
                    return false;
                return values.Contains(item);
            }
        }
    
        public void CopyTo(Titem[] array, int arrayIndex)
        {
            int i = arrayIndex;
            lock (_lock)
            {
                foreach (var list in _internalLists.Values)
                {
                    list.CopyTo(array, i);
                    i += list.Count;
                }
            }
        }
    
        public IEnumerator GetEnumerator()
        {
            foreach (var list in _internalLists.Values)
            {
                foreach (var item in list)
                    yield return item;
            }
        }
    
        public int IndexOf(Titem item)
        {
            int i = 0;
            var sortVal = _getSortValue(item);
            lock (_lock)
            {               
                foreach (var list in _internalLists)
                {
                    if (object.Equals(list.Key, sortVal))
                    {
                        int intIndex = list.Value.IndexOf(item);
                        if (intIndex == -1)
                            return -1;
                        return i + intIndex;
                    }
                    i += list.Value.Count;
                }
                return -1;
            }           
        }
    
        public void Insert(int index, Titem item)
        {
            throw new NotSupportedException();
        }
    
        // Note this method is indeterminate if there are multiple
        // items in the same sort position!
        public void RemoveAt(int index)
        {
            int i = 0;
            lock (_lock)
            {
                foreach (var list in _internalLists.Values)
                {
                    if (i + list.Count < index)
                    {
                        i += list.Count;
                        continue;
                    }
                    else
                    {
                        list.RemoveAt(index - i);
                        return;
                    }
                }
            }
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
    

提交回复
热议问题