Reputation: 83358
Is there a collection in C# that will not let you add duplicate items to it? For example, with the silly class of
public class Customer {
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public override int GetHashCode() {
return (FirstName + LastName + Address).GetHashCode();
}
public override bool Equals(object obj) {
Customer C = obj as Customer;
return C != null && String.Equals(this.FirstName, C.FirstName) && String.Equals(this.LastName, C.LastName) && String.Equals(this.Address, C.Address);
}
}
The following code will (obviously) throw an exception:
Customer Adam = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Customer AdamDup = new Customer { Address = "A", FirstName = "Adam", LastName = "" };
Dictionary<Customer, bool> CustomerHash = new Dictionary<Customer, bool>();
CustomerHash.Add(Adam, true);
CustomerHash.Add(AdamDup, true);
But is there a class that will similarly guarantee uniqueness, but without KeyValuePairs? I thought HashSet<T>
would do that, but having read the docs it seems that class is just a set implementation (go figure).
Upvotes: 152
Views: 144513
Reputation: 4829
As an overall check different methods here are 4 ways to check if the collection has not any duplicates:
public static bool LinqAny<T>(IEnumerable<T> enumerable)
{
HashSet<T> set = new();
return enumerable.Any(element => !set.Add(element));
}
public static bool LinqAll<T>(IEnumerable<T> enumerable)
{
HashSet<T> set = new();
return !enumerable.All(set.Add);
}
public static bool LinqDistinct<T>(IEnumerable<T> enumerable)
{
return enumerable.Distinct().Count() != enumerable.Count();
}
public static bool ToHashSet<T>(IEnumerable<T> enumerable)
{
return enumerable.ToHashSet().Count != enumerable.Count();
}
Upvotes: 1
Reputation: 4255
You may look into something kind of Unique List as follows
public class UniqueList<T>
{
public List<T> List
{
get;
private set;
}
List<T> _internalList;
public static UniqueList<T> NewList
{
get
{
return new UniqueList<T>();
}
}
private UniqueList()
{
_internalList = new List<T>();
List = new List<T>();
}
public void Add(T value)
{
List.Clear();
_internalList.Add(value);
List.AddRange(_internalList.Distinct());
//return List;
}
public void Add(params T[] values)
{
List.Clear();
_internalList.AddRange(values);
List.AddRange(_internalList.Distinct());
// return List;
}
public bool Has(T value)
{
return List.Contains(value);
}
}
and you can use it like follows
var uniquelist = UniqueList<string>.NewList;
uniquelist.Add("abc","def","ghi","jkl","mno");
uniquelist.Add("abc","jkl");
var _myList = uniquelist.List;
will only return "abc","def","ghi","jkl","mno"
always even when duplicates are added to it
Upvotes: 0
Reputation: 137398
How about just an extension method on HashSet?
public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
if (!hash.Add(item))
throw new ValueExistingException();
}
Upvotes: 19
Reputation: 57210
Just to add my 2 cents...
if you need a ValueExistingException-throwing HashSet<T>
you can also create your collection easily:
public class ThrowingHashSet<T> : ICollection<T>
{
private HashSet<T> innerHash = new HashSet<T>();
public void Add(T item)
{
if (!innerHash.Add(item))
throw new ValueExistingException();
}
public void Clear()
{
innerHash.Clear();
}
public bool Contains(T item)
{
return innerHash.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
innerHash.CopyTo(array, arrayIndex);
}
public int Count
{
get { return innerHash.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return innerHash.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
return innerHash.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
this can be useful for example if you need it in many places...
Upvotes: 4
Reputation: 1324
If all you need is to ensure uniqueness of elements, then HashSet is what you need.
What do you mean when you say "just a set implementation"? A set is (by definition) a collection of unique elements that doesn't save element order.
Upvotes: 5
Reputation: 112815
HashSet<T>
is what you're looking for. From MSDN (emphasis added):
The
HashSet<T>
class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
Note that the HashSet<T>.Add(T item)
method returns a bool
-- true
if the item was added to the collection; false
if the item was already present.
Upvotes: 277
Reputation: 498942
From the HashSet<T>
page on MSDN:
The HashSet(Of T) class provides high-performance set operations. A set is a collection that contains no duplicate elements, and whose elements are in no particular order.
(emphasis mine)
Upvotes: 15