I'm looking for a C# generic container that it's a List<T>
, but no repeated elements allowed.
In another word, it's a Set<T>
, but can also be accessed via [index]
operator.
Thanks.
I'm looking for a C# generic container that it's a List<T>
, but no repeated elements allowed.
In another word, it's a Set<T>
, but can also be accessed via [index]
operator.
Thanks.
As suggested in the comments, you could implement IList<T>
that delegates to an inner List<T>
instance, and guards add and remove calls with using a HashSet<T>
:
public class UniqueList<T> : IList<T>
{
private readonly List<T> list=new List<T>();
private readonly HashSet<T> set=new HashSet<T>();
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T item)
{
if(set.Add(item))
{
list.Add(item);
}
}
public void Clear()
{
set.Clear();
list.Clear();
}
public bool Contains(T item)
{
return set.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
list.CopyTo(array,arrayIndex);
}
public bool Remove(T item)
{
if(set.Remove(item))
{
list.Remove(item);
return true;
}
return false;
}
public int Count { get { return list.Count; } }
public bool IsReadOnly { get { return false; } }
public int IndexOf(T item)
{
return list.IndexOf(item);
}
public void Insert(int index, T item)
{
if(set.Add(item))
{
list.Insert(index, item);
}
}
public void RemoveAt(int index)
{
T item = list[index];
set.Remove(item);
list.RemoveAt(index);
}
public T this[int index]
{
get { return list[index]; }
set {
T item = list[index];
set.Remove(item);
if(set.Add(value))
{
list[index] = value;
}
else
{
set.Add(item);
throw new Exception();
}
}
}
}
I didn't compile this code, but you get the idea...
No such thing is provided in the framework (and HashSet<T>
does not guarantee any specific order, so you can't cheat with ElementAt
). The closest inbuilt you could use would be something like SortedList<T,anything>
(the "anything" there doesn't matter, and could be T
, int
, whatever), for example:
var data = new SortedList<string, int>();
data["abc"] = 1;
data["def"] = 1;
data["abc"] = 1;
var thisIsTrue = data.ContainsKey("def");
var thisIsFalse = data.ContainsKey("ghi");
for (int i = 0; i < data.Count; i++) // 2 iterations
Console.WriteLine(data.Keys[i]); // abc, def
However; it is important to note that the guaranteed order here is key order, not insertion order. The index of keys is available via data.IndexOfKey
.
You could use the OrderedDictionary. If you use your type for both key and value type, and use the same object as both key and value, you get the behavior you need (You could also use the keys collection for index based retrieval; and stick dummy data into the value, but I'm not sure what you would gain).