Click here to Skip to main content
15,881,380 members
Articles / Programming Languages / C#
Article

A Set class

Rate me:
Please Sign up or sign in to vote.
4.48/5 (11 votes)
20 Nov 2006CPOL3 min read 66.2K   361   28   21
A Set class using a System.Collections.Generic.Dictionary to hold its elements.

Introduction

This class implements a Set using a System.Collections.Generic.Dictionary to hold the elements.

Using the code

The zip file contains three C# files:

  • Set.cs contains the Set class definition.
  • GetTypes.cs contains the static method to get an array of types.
  • SortMode.cs contains the definition of the SortMode enumeration.

To use them, simply add them to your project. The following section describes how to use the class.

Empty instances of Set can be constructed with:

C#
Set<int> a = new Set<int>() ;
Set<char> b = new Set<char>() ;
Set<string> c = new Set<string>() ;

You may construct a Set to contain whatever type of items you require (limited only by the underlying System.Collections.Generic.Dictionary).

C#
Set<object> s = new Set<object>() ;
Set<int[]> s = new Set<int[]>() ;
Set<System.Data.DataRow> s = new Set<System.Data.DataRow>() ;
Set<System.EventHandler> s = new Set<System.EventHandler>() ;
Set<System.Collections.IEnumerable> s = 
       new Set<System.Collections.IEnumerable>() ;

Instances of Set can be constructed and initialized with:

C#
Set<int> s = new Set<int> ( 1 , 2 , 3 ) ;
Set<char> s = new Set<char> ( '1' , '2' , '3' ) ;
Set<string> s = new Set<string> ( "One" , "Two" , "Three" ) ;

Set<int> s = new Set<int> ( somearrayofints ) ;
Set<char> s = new Set<char> ( somearrayofchars ) ;
Set<string> s = new Set<string> ( somearrayofstrings ) ;

Set<int> s = somearrayofints ;
Set<char> s = somearrayofchars ;
Set<string> s = somearrayofstrings ;

The constructor can take any object of type object, but the converters* are somewhat more limited because converting from object or an interface is not allowed.

When an item that is not of the specified type is encountered, it is checked to see if it is IEnumerable, and if so, it will be foreached to recurse across it. This is how the arrays are handled in the above examples. If an object that is neither the target type nor IEnumerable is encountered** an InvalidOperationException is thrown.

Additional converters may be added as needed. And I'll point out that the class is partial so you may put any additional code in a separate file and not modify mine.

* Yes, I realize that having these conversions as implicit goes against the guidelines (because they could fail), but hey, it's my code and I'll do what I want. If you want them to be explicit, define explicit.

** Null items are ignored by default. If throwing NullReferenceExceptions for nulls is desired, define ThrowOnNull.

Once you've constructed instances, you may perform set operations on them:

| or + Union; { 1 , 2 , 3 } | { 2 , 4 , 6 } = { 1 , 2 , 3 , 4 , 6 }.

C#
a = b | c ;
a = b + c ;
a |= b ;
a += b ;

& Intersection; { 1 , 2 , 3 } & { 2 , 4 , 6 } = { 2 }.

C#
a = b & c ;
a &= b ;

- Relative complement; { 1 , 2 , 3 } - { 2 , 4 , 6 } = { 1 , 3 }.

C#
a = b - c ;
a -= b ;

== Equality.

C#
if ( a == b ) { ... }

!= Inequality.

C#
if ( a != b ) { ... }

<= Subset.

C#
if ( a <= b ) { ... }

< Subset but not equal.

C#
if ( a < b ) { ... }

>= Superset.

C#
if ( a >= b ) { ... }

> Superset but not equal.

C#
if ( a > b ) { ... }

The following public methods and properties are also available

Add ( params object[] Items ) attempts to add the items to the Set. In some cases, this is more efficient than using the Union operator.

C#
s.Add ( 1 ) ;
s.Add ( 1 , 2 ... ) ;
s.Add ( somearrayofints ) ;

Remove ( params object[] Items ) attempts to remove the items from the Set. In some cases, this is more efficient than using the relative complement operator.

C#
s.Remove ( 1 ) ;
s.Remove ( 1 , 2 ... ) ;
s.Remove ( somearrayofints ) ;

Contains ( params object[] Items ) returns true if the Set contains the item(s), otherwise false. In some cases, this is more efficient than using the subset operator.

C#
if ( s.Contains ( 1 ) ) { ... }
if ( s.Contains ( 1 , 2 ... ) ) { ... }
if ( s.Contains ( somearrayofints ) ) { ... }

Clear() removes all elements from the Set.

C#
s.Clear() ;

Cardinality is the number of elements in the Set.

C#
if ( s.Cardinality > 0 ) { ... }

EqualityComparer gets/sets the EqualityComparer of the underlying System.Collections.Generic.Dictionary.

C#
Set<string> s = new Set<string> ( "abc" , "ABC" ) ;
System.Console.WriteLine ( s.EqualityComparer.ToString() ) ;
System.Console.WriteLine ( s.ToString() ) ;
s.EqualityComparer = System.StringComparer.CurrentCultureIgnoreCase ;
System.Console.WriteLine ( s.EqualityComparer.ToString() ) ;
System.Console.WriteLine ( s.ToString() ) ;

Yields:

System.Collections.Generic.GenericEqualityComparer`1[System.String]
{ abc , ABC }
System.CultureAwareComparer
{ abc }

ToString() traverses the Set performing ToString() on each element and concatenating the resultant strings together in proper Set format: { element1 , element2... }.

C#
System.Console.Write ( s.ToString() ) ;

ToString ( SortMode SortMode , params object[] FormatInfo ) traverses the Set performing ToString ( FormatInfo ) on each element and concatenating the resultant strings together in proper Set format: { element1 , element2... }.

C#
Set<int> s = new Set<int> ( 20 , 3 , 100 ) ;

System.Console.WriteLine ( s.ToString ( SortMode.None   ) ) ;
System.Console.WriteLine ( s.ToString ( SortMode.Native ) ) ;
System.Console.WriteLine ( s.ToString ( SortMode.String ) ) ;
System.Console.WriteLine ( s.ToString ( SortMode.None   , "000" ) ) ;
System.Console.WriteLine ( s.ToString ( SortMode.Native , "000" ) ) ;
System.Console.WriteLine ( s.ToString ( SortMode.String , "000" ) ) ;

Yields:

{ 20 , 3 , 100 }
{ 3 , 20 , 100 }
{ 100 , 20 , 3 }
{ 020 , 003 , 100 }
{ 003 , 020 , 100 }
{ 003 , 020 , 100 }

Interfaces

IEnumerable GetEnumerator returns the GetEnumerator of the underlying System.Collections.Generic.Dictionary's Keys property.

C#
foreach ( int i in s ) { ... }

History

  • First submitted - 2006-11-14.
  • Updated 2006-11-15.
    • Added the ability to specify the EqualityComparer by using a Dictionary rather than a List.
    • Added the ability to specify formatting information to the ToString().

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
BSCS 1992 Wentworth Institute of Technology

Originally from the Boston (MA) area. Lived in SoCal for a while. Now in the Phoenix (AZ) area.

OpenVMS enthusiast, ISO 8601 evangelist, photographer, opinionated SOB, acknowledged pedant and contrarian

---------------

"I would be looking for better tekkies, too. Yours are broken." -- Paul Pedant

"Using fewer technologies is better than using more." -- Rico Mariani

"Good code is its own best documentation. As you’re about to add a comment, ask yourself, ‘How can I improve the code so that this comment isn’t needed?’" -- Steve McConnell

"Every time you write a comment, you should grimace and feel the failure of your ability of expression." -- Unknown

"If you need help knowing what to think, let me know and I'll tell you." -- Jeffrey Snover [MSFT]

"Typing is no substitute for thinking." -- R.W. Hamming

"I find it appalling that you can become a programmer with less training than it takes to become a plumber." -- Bjarne Stroustrup

ZagNut’s Law: Arrogance is inversely proportional to ability.

"Well blow me sideways with a plastic marionette. I've just learned something new - and if I could award you a 100 for that post I would. Way to go you keyboard lovegod you." -- Pete O'Hanlon

"linq'ish" sounds like "inept" in German -- Andreas Gieriet

"Things would be different if I ran the zoo." -- Dr. Seuss

"Wrong is evil, and it must be defeated." –- Jeff Ello

"A good designer must rely on experience, on precise, logical thinking, and on pedantic exactness." -- Nigel Shaw

“It’s always easier to do it the hard way.” -- Blackhart

“If Unix wasn’t so bad that you can’t give it away, Bill Gates would never have succeeded in selling Windows.” -- Blackhart

"Use vertical and horizontal whitespace generously. Generally, all binary operators except '.' and '->' should be separated from their operands by blanks."

"Omit needless local variables." -- Strunk... had he taught programming

Comments and Discussions

 
GeneralMy vote of 5 Pin
Gun Gun Febrianza10-Jun-16 5:08
Gun Gun Febrianza10-Jun-16 5:08 
GeneralRe: My vote of 5 Pin
PIEBALDconsult10-Jun-16 13:36
mvePIEBALDconsult10-Jun-16 13:36 
GeneralUnit Testing Pin
Friedrich Brunzema10-Feb-09 4:47
Friedrich Brunzema10-Feb-09 4:47 
GeneralRe: Unit Testing Pin
PIEBALDconsult10-Feb-09 4:57
mvePIEBALDconsult10-Feb-09 4:57 
Generalexception when comparing to null Pin
deerchao3-Nov-07 21:47
deerchao3-Nov-07 21:47 
GeneralRe: exception when comparing to null Pin
PIEBALDconsult4-Nov-07 4:27
mvePIEBALDconsult4-Nov-07 4:27 
GeneralRe: exception when comparing to null Pin
deerchao4-Nov-07 4:55
deerchao4-Nov-07 4:55 
GeneralRe: exception when comparing to null Pin
PIEBALDconsult4-Nov-07 6:21
mvePIEBALDconsult4-Nov-07 6:21 
GeneralRe: exception when comparing to null Pin
PIEBALDconsult4-Nov-07 7:24
mvePIEBALDconsult4-Nov-07 7:24 
Now I have it as

C#
# define NullEqualsNull
...
        public static bool
        operator ==
        (
            Set<T> lhs
        ,
            Set<T> rhs
        )
        {
            bool result    = false ;
            byte nullflags = 0     ;
            
            if ( Set<T>.IsNull ( lhs ) )
            {
                nullflags |= 1 ;
            }
 
            if ( Set<T>.IsNull ( rhs ) )
            {
                nullflags |= 2 ;
            }
            
# if NullEqualsNull            
 
            result = object.ReferenceEquals ( lhs , rhs ) ;
 
# else            
 
            result = ( nullflags == 0 ) && object.ReferenceEquals ( lhs , rhs ) ;
 
# endif
 
            if ( !result && ( nullflags == 0 ) )
            {
                result = ( lhs.Cardinality == rhs.Cardinality ) && lhs.Contains ( rhs ) ;
            }
 
            return ( result ) ;
        }



But I'm still not sure I want to add similar protection to the other operators.
GeneralRe: exception when comparing to null Pin
PIEBALDconsult4-Nov-07 8:33
mvePIEBALDconsult4-Nov-07 8:33 
GeneralRe: exception when comparing to null Pin
deerchao4-Nov-07 14:05
deerchao4-Nov-07 14:05 
GeneralStopped Reading... Pin
Drell Hearthbake14-Aug-07 3:44
Drell Hearthbake14-Aug-07 3:44 
GeneralRe: Stopped Reading... Pin
PIEBALDconsult14-Aug-07 13:53
mvePIEBALDconsult14-Aug-07 13:53 
GeneralRe: Stopped Reading... Pin
Rich Insley29-Aug-07 6:22
Rich Insley29-Aug-07 6:22 
QuestionOrdered Set Pin
Astrodata18-Apr-07 1:59
Astrodata18-Apr-07 1:59 
AnswerRe: Ordered Set Pin
PIEBALDconsult15-Aug-07 3:58
mvePIEBALDconsult15-Aug-07 3:58 
GeneralRe: Ordered Set Pin
Astrodata15-Aug-07 22:00
Astrodata15-Aug-07 22:00 
GeneralMuch appreciated! Pin
2Scott214-Apr-07 11:12
2Scott214-Apr-07 11:12 
GeneralRe: Much appreciated! Pin
PIEBALDconsult14-Apr-07 11:26
mvePIEBALDconsult14-Apr-07 11:26 
GeneralNice contribution Pin
PatB_Qc6-Dec-06 5:22
PatB_Qc6-Dec-06 5:22 
GeneralRe: Nice contribution Pin
PIEBALDconsult7-Dec-06 3:22
mvePIEBALDconsult7-Dec-06 3:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.