Set Operations with C# Generics

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

kick it on DotNetKicks.com



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&lt;TElement&gt;"/> class.
        /// </summary>
        public Set()
        {
            
        }
        
        /// <summary>
        /// Initializes a new instance of the <see cref="Set&lt;TElement&gt;"/> 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
    }
}