July 28, 2017

An Alternative Queue Class

Here is an alternative generic Queue class. I created it as I constantly found when using a queue class that Enqueue and Dequeue were never enough. There was always a need for a remove an item and a need to iterate through all the items in a queue. The original basic source for the queue class is here.
public class Node< T >
{
    public T Data { get; set; }
    public Node<T> Next { get; set; }

    public Node( T data )
    {
        this.Data = data;
    }
}

public class Queue2< T >
{
    private Node<T> _head;
    private Node<T> _tail;
    private int _count;
    private readonly IEqualityComparer<T> _comparator;

    public Queue2()
    {
        _comparator = EqualityComparer<T>.Default;
    }

    public Queue2( IEqualityComparer<T> comparator )
    {
        _comparator = comparator;
    }

    public void Enqueue(
        T data )
    {
        Node<T> _newNode = new Node<T>( data );
        if ( _head == null )
        {
            _head = _newNode;
            _tail = _head;
        }
        else
        {
            _tail.Next = _newNode;
            _tail = _tail.Next;
        }
        ++_count;
    }

    public T Dequeue()
    {
        if ( _head == null )
        {
            throw new Exception( "Queue is Empty" );
        }
        T _result = _head.Data;
        _head = _head.Next;
        --_count;
        return _result;
    }

    public void Remove(
        T item )
    {
        Node<T> previous = null, cursor = _head;
        bool found = false;
        while ( ( cursor != null ) && !found )
        {
            found = _comparator.Equals( cursor.Data, item );
            if ( found )
            {
                if ( previous == null )
                {
                    _head = cursor.Next;
                }
                else
                {
                    previous.Next = cursor.Next;
                }
                --count;
            }
            else
            {
                previous = cursor;
                cursor = cursor.Next;
            }
        }
    }

    public void Clear()
    {
        _head = _tail = null;
        count = 0;
    }

    public IEnumerable<T> GetEnumerator()
    {
        Node<T> cursor = _head;
        while ( cursor != null )
        {
            yield return cursor.Data;
            cursor = cursor.Next;
        }
    }

    public int Count
    {
        get { return this._count; }
    }
}

July 20, 2017

A String.Split() That Returns An IEnumerable

A version of Split string that returns an IEnumerable<string> rather than an array. Only single separate string is allowed, it is very rare that an array of separator strings is required.
  
public static class StringSplitExtensions
{
  
  public static IEnumerable<string> Split2(
    this string targetStr,
    string separator )
  {
    if ( targetStr == null )
      yield break;

    if ( string.IsNullOrEmpty( separator ) )
    {
      yield return targetStr;
    }
    else
    {
      string str = targetStr;
      bool finished = false;
      int startIx = 0;
      int sepLength = separator.Length;
      while ( !finished )
      {
        var ix = str.IndexOf( separator, 
            StringComparison.OrdinalIgnoreCase );
        if ( ix == -1 )
        {
          finished = true;
          yield return str;
        }
        else
        {
          string res = str.Substring( 0, ix );
          yield return res;
          startIx = ix + sepLength;
          str = str.Substring( startIx, str.Length - startIx );
        }
      }
    }
  }
}



[ Test ]
public void SplitTest()
{
  string test = "012 3456\t7890\ta  aaa\tbbbb\t";

  var res2 = test.Split2( "\t" ).ToArray();
  var norm2 = test.Split( '\t' );
  Assert.IsTrue( AreTheSame( res2, norm2 ) );

  var res3 = "".Split2( "\t" ).ToArray();
  var norm3 = "".Split( '\t' );
  Assert.IsTrue( AreTheSame( res3, norm3 ) );

  var res4 = "\t".Split2( "\t" ).ToArray();
  var norm4 = "\t".Split( '\t' );
  Assert.IsTrue( AreTheSame( res4, norm4 ) );

  var res5 = "\t\t".Split2( "\t" ).ToArray();
  var norm5 = "\t\t".Split( '\t' );
  Assert.IsTrue( AreTheSame( res5, norm5 ) );

  var res6 = "a\t".Split2( "\t" ).ToArray();
  var norm6 = "a\t".Split( '\t' );
  Assert.IsTrue( AreTheSame( res6, norm6 ) );

  var res7 = "\ta".Split2( "\t" ).ToArray();
  var norm7 = "\ta".Split( '\t' );
  Assert.IsTrue( AreTheSame( res7, norm7 ) );

  // Works the same as a standard Split string except in 
  // the case where the Splitter string is an empty string
  var norm8 = test.Split();
  var res8 = test.Split2( "" ).ToArray();
  Assert.IsFalse( AreTheSame( res8, norm8 ) );
}


// Checks whether 2 string arrays are exactly the same, ie. they have
// the same length and the same values at each array entry
public static bool AreTheSame(
string[] stringArray1,
string[] stringArray2)
{
  bool areTheSame = (stringArray1.Length == stringArray2.Length);
  for (int ix = 0; (ix < stringArray1.Length) && areTheSame; ix++)
  {
    areTheSame = stringArray1[ix].Equals(stringArray2[ix], StringComparison.CurrentCulture);
  }
  return areTheSame;
}