The Wonderful World of List<T>

By John Belthoff / In Web / Posted Oct 16, 2009

The List<T>

About 2 years ago I stumbled upon the little gem known as the Generic List. To be specific; System.Collections.Generic.List. It is my hope after your done reading this series of articles that you will come to stop using the bloated ADO.Net objects and start writing efficient code. Stick with me to find out!

This little baby has given me more trouble, performance gain and everything else imaginable and because of this I thought I would sing its praises this to you this afternoon in a series of articles.

Let's take this puppy for a ride! Create a test page and add the following to the using block; using System.Collections.Generic; and then let's stuff our list with some data.

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class list_t : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        List<string> l = new List<string>();
        for (int i = 0; i < 100000; i++)
        {
            l.Add(i.ToString());
        }
        Response.Write(l.Count.ToString());
    }
}

As you can see we have a list of 100 thousand strings. Simple enough right? Ok let's try to find a value in that list and measure some performance. First we will turn on our Asp.Net trace in the .aspx page and run some basic code to look for values in our list.

        List<string> l = new List<string>();
        for (int i = 0; i < 100000; i++)
        {
            l.Add(i.ToString());
        }

        Trace.Warn("Contains", "Starting");
        if (l.Contains("49999"))
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("Contains", "Ended");

        Trace.Warn("Contains", "Starting");
        if (l.Contains("95842584147"))
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("Contains", "Ended");

On my machine I am finding, or not finding, that value in between 0.001270 and 0.002004 which is not bad. What's a couple of milliseconds between friends? But let's see if we can speed things up a bit and to do that we need to sort our list and try again using the binary search method of our List.

        l.Sort();

        Trace.Warn("BinarySearch", "Starting");
        if(l.BinarySearch("99799") > -1 )
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("BinarySearch", "Ended");

Ah now by sorting our list and using the binary search I have just scanned a 100 thousand row record set in about 60 uSecs: 0.000068 in the application side. Not bad for an old guy huh?

Now I know what you're asking... What does this all mean? Well, say goodbye to all of those bloated ADO.net methods! Stick with me in my next addition and I will explain why I have come to that conclusion.

For now... Happy coding!

Aspx:

<%@ Page Language="C#" AutoEventWireup="true" trace="true" CodeFile="list-t.aspx.cs" Inherits="list_t" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    </div>
    </form>
</body>
</html>

C#:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class list_t : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Create our List
        List<string> l = new List<string>();
        
        // Stuff it with Data
        for (int i = 0; i < 100000; i++)
        {
            l.Add(i.ToString());
        }
        Response.Write(l.Count.ToString());

        // Measure Performance With
        Trace.Warn("Contains", "Starting");
        if (l.Contains("49999"))
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("Contains", "Ended");

        // Measure Performance Without
        Trace.Warn("Contains", "Starting");
        if (l.Contains("95842584147"))
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("Contains", "Ended");

        // Sort our List
        l.Sort();
        
        // Measure Performance After Sorting our list
        Trace.Warn("BinarySearch", "Starting");
        if(l.BinarySearch("99799") > -1 )
            Response.Write("Yes");
        else
            Response.Write("No");
        Trace.Warn("BinarySearch", "Ended");

    }
}