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
}
}
October 17, 2007 at 9:32 am
Did you try out NGenerics? They contain lots of the features that are missing from System.Collections.Generics
October 17, 2007 at 3:09 pm
NHibernate comes with an assembly call Iesi.Collections, which contains a number of different implementations of ISet. If you just want a set, then surely that’d do it?
October 17, 2007 at 5:58 pm
The free PowerCollections library also has a set.
.NET 3.5 has a generic HashSet collection.
October 21, 2007 at 11:16 pm
[...] is a good article on Set Operations with C# Generics by Gerhard [...]
August 18, 2008 at 4:27 am
Short, clear and straight implementation. Its nice filling .NET gaps.
September 19, 2008 at 1:27 pm
Thanks,
I was missing this!
Very useful.
You could add implementation of symmetric difference.
And the fastest way to compute it, is not the union minus the intersection by the way.