Blog RegisterLogin
Menu
 
Hosted by Webhost4life
Tags: IT , Blog , C# , Collecions
Blog
<<  31 Days of Refactoring  |  Home  |  Tagged Content FAQ  >>

Oct 23

Written by: Tomasz Modelski
2009-10-23 15:41:12Z 

Few months ago I’ve published first version of my ListUnique.
ListUnique is .Net C# generic list which keeps insertion order, you can iterate through it and it has only unique values, with IListUnique interface.

Below is next version, with unit tests.
What’s new :

  • new methods AddUniqueOnly & AddRangeUniqueOnly – those methods will add only unique values, won’t throw exception if value is already in list.
    Just add unique values and omit existing ones.

This post is also online test of SyntaxHighlighter.
I’ve integrated it with DotNetNuke Blog module.
Within few days I’ll release this module (called BlogPlus) – it contains fixes & modifications & new features for core Blog module, SyntaxHighlighter is one of new features.

using System;
using System.Collections.Generic;


namespace TM.Common.Collections
{
	/// <summary>
	/// List that allows only unique values
	/// </summary>
	/// <typeparam name="T">Must implement IComparable T </typeparam>
	public class ListUnique<T> : List<T>, IListUnique<T> where T : IComparable<T>
	{
		
		public new void Add(T item)
		{	
			if( Exists(itemList => itemList.CompareTo(item) == 0) )
			{
				throw new ArgumentException("Cannot add not unique value to collection");
			}
			
			base.Add(item);
		}
		
		/// <summary>
		/// Adds element only if is unique
		/// </summary>
		/// <param name="item"></param>
		/// <returns>Return added or not</returns>
		public bool AddUniqueOnly(T item)
		{
			if( Exists(itemList => itemList.CompareTo(item) == 0) )
				return false;
			
			base.Add(item);
			return true;
		}

		/// <summary>
		/// Adds elements of the specified collection to the end of the list
		/// </summary>
		/// <param name="coll"></param>
		public new void AddRange(IEnumerable<T> coll)
		{
			foreach (T item in coll)
			{
				Add(item);
			}
		}

		/// <summary>
		/// Adds only unique elements of the specified collection to the end of the list
		/// </summary>
		/// <param name="coll"></param>
		public void AddRangeUnique(IEnumerable<T> coll)
		{
			foreach (T item in coll)
			{
				try
				{
					Add(item);
				}
				catch (ArgumentException)
				{  }
			}
		}

		public List<T> ToList()
		{
			return this;
		}

		public ListUnique(IEnumerable<T> collection)
		{
			foreach (T t in collection)
			{
				Add(t);
			}
		}

		public ListUnique(int capacity): base(capacity)
		{
		}

		public ListUnique()
		{
		}
	}

	/// <summary>
	/// IList that allows only unique values
	/// </summary>
	/// <typeparam name="T">Must implement IComparable T </typeparam>
	public interface IListUnique<T> : IList<T> where T : IComparable<T>
	{
		List<T> ToList();

		bool AddUniqueOnly(T item);

		/// <summary>
		/// Adds elements of the specified collection to the end of the list, throws exception on unique violation
		/// </summary>
		/// <param name="coll"></param>
		void AddRange(IEnumerable<T> coll);

		/// <summary>
		/// Adds only unique elements of the specified collection to the end of the list
		/// </summary>
		/// <param name="coll"></param>
		void AddRangeUnique(IEnumerable<T> coll);
	}
}

And Unit tests:

using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace TM.Common.Collections.Tests
{
	[TestFixture]
	public class ListUnique_Test
	{
		[Test]
		public void CreateNew()
		{
			IListUnique<string> listUnique = new ListUnique<string>();
		}
		
		[Test]
		public void AddUniqueValues()
		{
			IListUnique<string> listUnique = new ListUnique<string>();
			
			listUnique.Add("a");
			listUnique.Add("b");
			listUnique.Add("c");
			listUnique.Add("d");
			
			Assert.AreEqual(4,listUnique.Count);
			Assert.AreEqual("a",listUnique[0]);
			Assert.AreEqual("d", listUnique[3]);
		}
		
		[Test]
		public void AddUniqueOnly_Basic()
		{
			IListUnique<int> listUnique = new ListUnique<int>();
			
			listUnique.AddUniqueOnly(1);
			listUnique.AddUniqueOnly(2);
			listUnique.AddUniqueOnly(3);
			listUnique.AddUniqueOnly(4);

			bool addStatus;
			
			addStatus=listUnique.AddUniqueOnly(3);
			Assert.IsFalse(addStatus);
			
			Assert.AreEqual(4,listUnique.Count);
		}
		
		[Test]
		public void AddRangeUnique()
		{
			List<string> list = new List<string>();
			list.Add("a");
			list.Add("b");
			list.Add("c");
			list.Add("d");
			
			IListUnique<string> listUnique = new ListUnique<string>();

			listUnique.AddRange(list);

			Assert.AreEqual(4, listUnique.Count);
			Assert.AreEqual("a", listUnique[0]);
			Assert.AreEqual("d", listUnique[3]);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void AddRangeNotUnique_ExceptionExpected()
		{
			List<string> list;
			
			list = new List<string>();
			list.Add("a");
			list.Add("b");
			list.Add("c");
			list.Add("d");

			IListUnique<string> listUnique = new ListUnique<string>();

			listUnique.AddRange(list);

			list = new List<string>();
			list.Add("e");
			list.Add("f");
			list.Add("a");	// <- not unique
			list.Add("h");

			listUnique.AddRange(list); // <- exception expected
		}

		[Test]
		public void AddRangeUnique_NotUnique()
		{
			List<string> list;

			list = new List<string>();
			list.Add("a");
			list.Add("b");
			list.Add("c");
			list.Add("d");

			IListUnique<string> listUnique = new ListUnique<string>();

			listUnique.AddRange(list);

			list = new List<string>();
			list.Add("e");
			list.Add("f");
			list.Add("a");	// <- not unique
			list.Add("h");

			listUnique.AddRangeUnique(list);
			
			Assert.AreEqual( 7 ,listUnique.Count);
			Assert.AreEqual("a", listUnique[0]);
			Assert.AreEqual("d", listUnique[3]);
			Assert.AreEqual("h", listUnique[6]);
		}
		
		[Test]
		public void CreateFromUniqueList()
		{
			List<string> list=new List<string>();
			list.Add("a");
			list.Add("b");
			list.Add("c");
			list.Add("d");

			IListUnique<string> listUnique = new ListUnique<string>(list);

			Assert.AreEqual(4, listUnique.Count);
			Assert.AreEqual("a", listUnique[0]);
			Assert.AreEqual("d", listUnique[3]);
		}
		
		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void AddNonUnique()
		{
			IListUnique<string> listUnique = new ListUnique<string>();

			listUnique.Add("a");
			listUnique.Add("b");
			listUnique.Add("b");
			listUnique.Add("d");

			Assert.AreEqual(3, listUnique.Count);
			Assert.AreEqual("a", listUnique[0]);
			Assert.AreEqual("d", listUnique[2]);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void CreateFromNotUniqueList()
		{
			List<string> list = new List<string>();
			list.Add("a");
			list.Add("b");
			list.Add("b");
			list.Add("d");

			IListUnique<string> listUnique = new ListUnique<string>(list);

			Assert.AreEqual(3, listUnique.Count);
			Assert.AreEqual("a", listUnique[0]);
			Assert.AreEqual("d", listUnique[2]);
		}
	}
}

Tags:

3 comment(s) so far...

Re: ListUnique-generic List with unique values in .Net C# part 2

you have a very good blog, congratulations.
I have a question : What dose "S.O.L.I.D. developer" mean?

By Parastou on   2009-10-28 20:12:08Z

Re: ListUnique-generic List with unique values in .Net C# part 2

Parastou, S.O.L.I.D is a shortcut for 5 good practices (principles):
- Single Responsibility Principle
- Open Close Principle
- Liskov Substitution Principle
- Interface Segregation Principle-Dependency Inversion Principle

See for detailed reference: www.lostechies.com/blogs/chad_myers/archive/2008/03/07/pablo-s-topic-of-the-month-march-solid-principles.aspx

Using SOLID principles improves your architecture & code quality, code managebility, etc.

By Tomasz Modelski on   2009-10-29 14:53:44Z

Re: ListUnique-generic List with unique values in .Net C# part 2

I noticed the List ToList(); is implemented but not tested. You might want to throw that in, some dopes (me) may not know what happens when you call a "new" method on a base class pointer. It seems counter-intuitive that simply casting is enough, and though I guess it is, the need for a "ToList" method on a List class seems redundant. Anyhoo, thought it worth mentioning..

Thanks!

James

By James White on   2009-12-04 22:04:59Z

Your name:
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
Enter the code shown above in the box below
Add Comment   Cancel 
 
Related content
 
Search_Blog
 
Blog Tags
 
Blog_Archive
 
Related