C#: String to Integer, Decimal, Float, or Any Type of Array or List


The string.Split method is a great tool that can be used when manipulating strings. But, this method simply returns an array of strings when frequently I need a collection returned in the type that the strings actually represent. To fix this you simply have to loop through each item in the string array and convert it to its representative type. For example, if you are reading in a comma delimited file of temperatures, you can split on the commas and then loop through the returned array, parsing each element and adding it to a new list, as follows:


string temperatures = "67.2,92.1,78.2,100.3,89.2";

string[] tempArray = temperatures.Split(',');

List<float> temps = new List<float>();
foreach (string temp in tempArray)
    temps.Add(float.Parse(temp));

While such a solution is common and quite acceptable, I wanted to make it simpler and reusable. To do such, I decided to implement the above logic in a generic extension method.


/// <summary>
/// Splits a string using the supplied separator and casts each element to the
/// indicated type.
/// </summary>
/// <typeparam name="T">The type of the List to return</typeparam>        
/// <param name="s">The string on which the operation will be performed.</param>
/// <param name="separator">An array of strings that delimit the substrings in this string, an empty
///     array that contains no delimiters, or null.</param>
/// <returns>A List of type T containing the elements formed after splitting the string using
/// the given separators.</returns>
public static List<T> SplitToList<T>(this string s, params string[] separator)
{
    return s.SplitToList<T>(StringSplitOptions.None, separator);
}

/// <summary>
/// Splits a string using the supplied separator and casts each element to the
/// indicated type.
/// </summary>
/// <typeparam name="T">The type of the List to return</typeparam>        
/// <param name="s">The string on which the operation will be performed.</param>
/// <param name="options">Specify System.StringSplitOptions.RemoveEmptyEntries to omit empty array
///     elements from the array returned, or System.StringSplitOptions.None to include
///     empty array elements in the array returned.</param>
/// <param name="separator">An array of strings that delimit the substrings in this string, an empty
///     array that contains no delimiters, or null.</param>
/// <returns>A List of type T containing the elements formed after splitting the string using
/// the given separators.</returns>
public static List<T> SplitToList<T>(this string s, StringSplitOptions options, params string[] separator)
{
    // Split the string based on the supplied separators
    string[] array = s.Split(separator, options);
    
    List<T> values = new List<T>();

    // Convert each element in the array to the indicated type
    foreach (string element in array)
        values.Add((T)Convert.ChangeType(element, typeof(T)));                

    return values;
}

Now our temperature example can be reduced to the following:


string temperatures = "67.2,92.1,78.2,100.3,89.2";
List<float> temps = temperatures.SplitToList<float>(",");

Below are some other examples of how this extension method could be used:

string s1 = "true-false-true-true-true-false";
List<bool> bools = s1.SplitToList<bool>("-");

string s2 = "a b c d e f g h i j";
List<char> chars = s2.SplitToList<char>(" ");

// Split on both commas and periods
string s3 = "1,3,4.5.7,1.4,6.7,8.2";
List<int> ints = s3.SplitToList<int>(",", ".");

C#: List.Contains Method – Case Insensitive


I had a list of strings and needed to check whether or not a specific string was contained within the list ignoring the character casing.  Pre-LINQ days you would have had to loop through the entries calling the .ToLower or ToUpper method on each of the elements or using the string.Compare method.  But thanks to LINQ, one simple method will take care of this for us:

List<string> list = new List<string>() { "a", "b", "c", "d", "e" };
string value = "A";

if (list.Contains(value, StringComparer.OrdinalIgnoreCase))
    Console.WriteLine(value + " is in the list!");
else
    Console.WriteLine(value + " is not in the list!");

C#: Most Recently Used List


I wanted to add a button to one of the applications that I wrote that listed the last ten reports that a user has viewed so they could quickly and easily access recently viewed reports. I found a lot of information about how to create a Most Recently Used (MRU) list of files that have been opened but I couldn’t find anything built into the .NET Framework to create a custom list of objects where the most recently used item was at the beginning of the list.

I’m sure many of you are saying to yourself, “Why didn’t he just use a stack?”. The reason I didn’t use the already built Stack class is because I needed to implement two other features:

  • Restrict the size of the set
  • Ensure no duplicate items exist in the set

The Stack class found in the System.Collections namespace doesn’t enforce these two properties inherently and thus the need for a custom collection.

Note: I could have optimized this collection a bit more by adding each item to the end of the list and keeping a pointer to the location of the true first item but given the fact that I only will be storing a few items in the set, I didn’t take the time to implement it that way. I leave that optimization to you.

/// <summary>
/// Stores a set of items with the most recently added at item the front and the 
/// least recently added item at the end
/// </summary>
public class RecentSet<T> : IEnumerable<T>
{
    private List<T> _list;
    private int _size = -1;

    /// <summary>
    /// Creates a new RecentSet object.
    /// </summary>
    public RecentSet()
    {
        _list = new List<T>();            
    }
     /// <summary>
    /// Creates a new RecentSet object with a fixed size. The return set may be smaller than
    /// the specified size but it will never be larger
    /// </summary>
    /// <param name="size">The maximum size of the set</param>
    public RecentSet(int size)
    {
        _list = new List<T>();
        _size = size;
    }
 
    /// <summary>
    /// Creates a new RecentSet object initializing it with the indicated items. Note: 
    /// the initialized RecentSet will be in the order of parameter items.  If items are {1, 2, 3, 4},
    /// iterating through RecentSet will result in a list of {1, 2, 3, 4} not {4, 3, 2, 1}        
    /// </summary>
    public RecentSet(IEnumerable<T> items)
    {
        _list = items.ToList();
    }

    /// <summary>
    /// Creates a new RecentSet object with a fixed size initializing it with the indicated items. Note: 
    /// the initialized RecentSet will be in the order of parameter items.  If items are {1, 2, 3, 4},
    /// iterating through RecentSet will result in a list of {1, 2, 3, 4} not {4, 3, 2, 1}        
    /// </summary>
    public RecentSet(int size, IEnumerable<T> items)
    {
        _list = items.ToList();
        _size = size;

        TrimList();
    }

    /// <summary>
    /// Adds an item to the RecentSet
    /// </summary>
    public void Add(T item)
    {
        // If the item is already in the set, remove it
        int i = _list.IndexOf(item);
        if (i > -1)
            _list.RemoveAt(i);

        // Add the item to the front of the list.
        _list.Insert(0, item);

        TrimList();
    }

    public int Count
    {
        get { return _list.Count; }
    }

    private void TrimList()
    {
        // If there is a set size, make sure the set only contains that many elements
        if (_size != -1)
            while (_list.Count > _size)
                _list.RemoveAt(_list.Count - 1);
    }

    /// <summary>
    /// Returns the set in the form of a List
    /// </summary>
    public List<T> ToList()
    {
        return _list;
    }

    #region IEnumerable<T> Members

     public IEnumerator<T> GetEnumerator()
    {           
        return _list.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    #endregion
}