C# Generics are powerful, but there are not many generic classes beyond List and Dictionary. Especially for Set Operations Generics are missing.
That’s whay I created a small class for Set Operations called Set that contains the basic Set Operations, like Union, Intersect and Difference.
Here’s a small example how to use it:
public enum DataSource
{
Database, XML, File, Stream, Http, Ftp
}static void Main(string[] args)
{
Set<DataSource> firstSet = new Set<DataSource>(
DataSource.Database, DataSource.File, DataSource.XML);
Set<DataSource> secondSet = new Set<DataSource>(
DataSource.Http, DataSource.Ftp, DataSource.Stream, DataSource.XML, DataSource.File);
Set<DataSource> union = firstSet.Union(secondSet);
// result = Database, File, Xml, Http, Ftp, Stream
Set<DataSource> intersect = firstSet.Intersect(secondSet);
// result = Xml, File
Set<DataSource> difference = firstSet.Difference(secondSet);
// result = Http, Ftp, Stream
}
And below you’ll find the complete implementation.
Cheers
- Gerhard
using System.Collections;
using System.Collections.Generic;
namespace SetExample
{
/// <summary>
/// Set class
/// </summary>
/// <typeparam name="TElement"></typeparam>
public class Set<TElement> : ICollection<TElement>
{
private List<TElement> internalList = new List<TElement>();
/// <summary>
/// Initializes a new instance of the <see cref="Set<TElement>"/> class.
/// </summary>
public Set()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Set<TElement>"/> class.
/// </summary>
/// <param name="elements">The elements.</param>
public Set(params TElement[] elements)
{
AddRange(elements);
}
/// <summary>
/// Adds the range.
/// </summary>
/// <param name="range">The range.</param>
public void AddRange(IEnumerable<TElement> range)
{
foreach (TElement element in range)
Add(element);
}
/// <summary>
/// Unions the specified set.
/// </summary>
/// <param name="set">The set.</param>
/// <returns></returns>
public Set<TElement> Union(Set<TElement> set)
{
Set<TElement> result = new Set<TElement>();
result.AddRange(this);
result.AddRange(set);
return result;
}
/// <summary>
/// Intersects the specified set.
/// </summary>
/// <param name="set">The set.</param>
public Set<TElement> Intersect(Set<TElement> set)
{
Set<TElement> result = new Set<TElement>();
foreach (TElement element in set)
if (Contains(element))
result.Add(element);
return result;
}
/// <summary>
/// Differences the specified set.
/// </summary>
/// <param name="set">The set.</param>
/// <returns></returns>
public Set<TElement> Difference(Set<TElement> set)
{
Set<TElement> result = new Set<TElement>();
foreach (TElement element in set)
if (!Contains(element))
result.Add(element);
return result;
}
/// <summary>
/// Gets or sets the <see cref="TElement"/> at the specified index.
/// </summary>
/// <value></value>
public TElement this[int index]
{
get { return internalList[index]; }
set { internalList[index] = value; }
}
#region ICollection<TElement> Members
public void Add(TElement item)
{
if (!Contains(item))
internalList.Add(item);
}
public void Clear()
{
internalList.Clear();
}
public bool Contains(TElement item)
{
return internalList.Contains(item);
}
public void CopyTo(TElement[] array, int arrayIndex)
{
internalList.CopyTo(array, arrayIndex);
}
public bool Remove(TElement item)
{
return internalList.Remove(item);
}
public int Count
{
get { return internalList.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region IEnumerable<TElement> Members
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
{
return internalList.GetEnumerator();
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return internalList.GetEnumerator();
}
#endregion
}
}