这样的集合是否存在(来自Dictionary& HashSet的功能)?

时间:2015-06-06 18:13:37

标签: c# list dictionary collections hashset

我正在寻找一个集合,其中没有元素可以存在多次,并且也被索引。与Dictionary类似,但没有Key,只有Value。与HashSet类似,但已建立索引,因此我可以轻松检索元素而无需迭代集合。我希望这是有道理的。 :)

4 个答案:

答案 0 :(得分:2)

您可以使用HashSet。它被“索引”,毕竟,如果不是,那么表现就会缺乏。

使用Contains方法“检索”元素。如果您也想删除它,请使用Remove

这两种方法都是O(1)操作。

答案 1 :(得分:1)

您可以使用Dictionary<T, T>并使用Add(value, value)插入元素。

但是,只有在您的类型正确实现Equals(object)GetHashCode()时才有意义。如果它没有,则两个不同的实例将永远不会相等,而HashSet<T>&#39; Contains(T)方法已经告诉您是否具有nor的元素引用。

答案 2 :(得分:0)

HashSet类最适合您的工作。我不会允许重复输入。 请注意,如果项目已添加到集合中,HashSet.Add(T item)方法将返回 bool - true ;如果项目已经存在,则 false

只需添加一个Extension方法即可将异常抛出为

 public static void AddOrThrow<T>(this HashSet<T> hash, T item)
    {
        if (!hash.Add(item))
            throw new ValueExistingException();
    }

答案 3 :(得分:0)

最简单的方法是创建一个实现IList<T>但在内部使用List<T>HashSet<T>的类。然后,您可以根据需要对每个集合执行每个方法。

using System;
using System.Collections.Generic;

namespace Example
{
    public class UniqueList<T> : IList<T>
    {
        private readonly List<T> _list;
        private readonly HashSet<T> _hashset;

        public UniqueList()
        {
            _list = new List<T>();
            _hashset = new HashSet<T>();
        }

        public UniqueList(IEqualityComparer<T> comparer)
        {
            _list = new List<T>();
            _hashset = new HashSet<T>(comparer);
        }

        void ICollection<T>.Add(T item)
        {
            Add(item);
        }

        public bool Add(T item)
        {
            var added = _hashset.Add(item);
            if (added)
            {
                _list.Add(item);
            }
            return added;
        }

        public void RemoveAt(int index)
        {
            _hashset.Remove(_list[index]);
            _list.RemoveAt(index);
        }

        public T this[int index]
        {
            get { return _list[index]; }
            set
            {
                var oldItem = _list[index];
                _hashset.Remove(oldItem);
                var added = _hashset.Add(value);
                if (added)
                {
                    _list[index] = value;
                }
                else
                {
                    //Put the old item back before we raise a exception.
                    _hashset.Add(oldItem);
                    throw new InvalidOperationException("Object already exists.");
                }
            }
        }

        public int IndexOf(T item)
        {
            return _list.IndexOf(item);
        }

        void IList<T>.Insert(int index, T item)
        {
            Insert(index, item);
        }

        public bool Insert(int index, T item)
        {
            var added = _hashset.Add(item);
            if (added)
            {
                _list.Insert(index, item);
            }
            return added;
        }

        public void Clear()
        {
            _list.Clear();
            _hashset.Clear();
        }

        public bool Contains(T item)
        {
            return _hashset.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            var removed = _hashset.Remove(item);
            if (removed)
            {
                _list.Remove(item);
            }
            return removed;
        }

        public int Count
        {
            get { return _list.Count; }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

    }
}

我做了AddInsert的显式实现,所以我可以给它们返回bool的版本来判断操作是否成功。我无法在T this[int index] setter中返回值,因此如果您尝试插入副本,我会抛出InvalidOperationException

如果您对副本执行ICollection.Add,它就不会抛出,它只是不添加它。这是因为这是行为HashSet<T>.ICollection<T>.Add,我想模仿它。