LinqTo2dArray

LinqTo2dArray written in C# (to allow iteration over the rows). Also found on CodePlex.

  • Parse will take a 2D Array (not necessarily zero based) and load it into a class. Parse 2D object array into a class row wise.
  • Compose will create 2D object array from enumerable type.
  • Copies the elements of the 2D object array row wise to a new array of the specified element type and length.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqTo2dArray
{
    public static class Array2dExtensions
    {

       /// <summary>
       /// Parse 2D object array into a class row wise.
       /// </summary>
        /// <typeparam name="TSource">New enumerable type.</typeparam>
        /// <param name="array">The two-dimensional Array to loop throug
h.</param>
        /// <param name="conversion">Conversion function to TSource type
.</param>
        /// <param name="rowStart">First row index to start.</param>
        /// <param name="columnStart">First column index to start.</para
m>
        /// <param name="rowCount">Number of rows.</param>
        /// <param name="columnCount">Number of columns</param>
        /// <example>
        ///  array.Parse(Of SaleOrder)(Function(o As Object()) New SaleO
rder( _
        ///                                     If(TypeOf o(0) Is Double
, Date.FromOADate(o(0)), #1/1/1900#) _
        ///                                     , If(Not TypeOf o(1) Is
Integer, o(1).ToString, "") _
        ///                                     , If(Not TypeOf o(2) Is
Integer, o(2).ToString, "") _
        ///                                     , If(Not TypeOf o(3) Is
Integer, o(3).ToString, "") _
        ///                                     , If(IsNumeric(o(4)) And
Also Not TypeOf o(4) Is Integer, CInt(o(4)), 0) _
        ///                                     , If(IsNumeric(o(5)) And
Also Not TypeOf o(5) Is Integer, o(5), 0) _
        ///                                     , o(6) + rowOffset _
        ///                                     ))
        ///   Note: Last index returns row number.
        /// </example>
        /// <exception cref="IndexOutOfRangeException">Parameters are ou
t of range of 2D array object.</exception>
        /// <returns>Enumerable of TSource</returns>
        /// <remarks>Jon Nyman 130205</remarks>
        public static IEnumerable<TSource> Parse<TSource>(this object[,]
 array, Func<object[], TSource> conversion
            , int rowStart, int columnStart, int rowCount, int columnCou
nt)
        {

            //Make sure values are within range of array.
            if (rowStart < 0 || columnStart < 0 || rowStart > array.GetU
pperBound(0) || columnStart > array.GetUpperBound(1) ||
                rowCount < 1 || rowCount + rowStart - 1 > array.GetUpper
Bound(0) || columnCount < 1 || columnCount + columnStart - 1 > array.Get
UpperBound(1))
                throw new System.IndexOutOfRangeException("Start or end
values out of range (Parse)");

            //Put 2D array values in a 1D array for conversion
            for (int row = rowStart; row < rowCount + rowStart; row++)
            {
                object[] array1d = new object[columnCount + 1];
                for (int column = columnStart; column < columnCount + co
lumnStart; column++)
                {
                    array1d[column - columnStart] = array[row, column];
                }
                //Add row number to the end of the 1D array.
                array1d[columnCount] = row;
                yield return conversion(array1d);
            }

        } //End Parse

        /// <summary>
        /// Parse 2D object array into a class row wise.
        /// </summary>
        /// <typeparam name="TSource">New enumerable type.</typeparam>
        /// <param name="array">The two-dimensional Array to loop throug
h.</param>
        /// <param name="conversion">Conversion function to TSource type
.</param>
        /// <example>
        ///  array.Parse(Of SaleOrder)(Function(o As Object()) New SaleO
rder( _
        ///                                     If(TypeOf o(0) Is Double
, Date.FromOADate(o(0)), #1/1/1900#) _
        ///                                     , If(Not TypeOf o(1) Is
Integer, o(1).ToString, "") _
        ///                                     , If(Not TypeOf o(2) Is
Integer, o(2).ToString, "") _
        ///                                     , If(Not TypeOf o(3) Is
Integer, o(3).ToString, "") _
        ///                                     , If(IsNumeric(o(4)) And
Also Not TypeOf o(4) Is Integer, CInt(o(4)), 0) _
        ///                                     , If(IsNumeric(o(5)) And
Also Not TypeOf o(5) Is Integer, o(5), 0) _
        ///                                     , o(6) + rowOffset _
        ///                                     ))
        ///   Note: Last index returns row number.
        /// </example>
        /// <exception cref="IndexOutOfRangeException">Parameters are ou
t of range of 2D array object.</exception>
        /// <returns>Enumerable of TSource</returns>
        /// <remarks>Jon Nyman 130205</remarks>
        public static IEnumerable<TSource> Parse<TSource>(this object[,]
 array, Func<object[], TSource> conversion)
        {

            int rowStart=array.GetLowerBound(0);
            int colStart=array.GetLowerBound(1);
            int rowCount=array.GetUpperBound(0)-rowStart+1;
            int colCount=array.GetUpperBound(1)-colStart+1;

            return array.Parse<TSource>(conversion, rowStart, colStart,
rowCount, colCount);

        }

         /// <summary>
        /// Copies the elements of the 2D object array row wise to a new
 array of the specified element type and length.
        /// </summary>
        /// <typeparam name="T">New array type.</typeparam>
        /// <param name="array">The two-dimensional object array.</param
>
        /// <param name="conversion">Casting function of new type.</para
m>
        /// <param name="rowStart">First row index to start.</param>
        /// <param name="columnStart">First column index to start.</para
m>
        /// <param name="rowCount">Number of rows.</param>
        /// <param name="columnCount">Number of columns</param>
        /// <returns>One-dimensional array of type TSource</returns>
        /// <remarks> Jon Nyman 20130205
        /// Source http://msmvps.com/blogs/jon_skeet/archive/2011/01/02/
reimplementing-linq-to-objects-part-24-toarray.aspx </remarks>
        public static T[] ToArray<T>(this object[,] array, Func<object,
T> conversion
                                                , int rowStart, int colu
mnStart, int rowCount, int columnCount)
        {
            //Make sure values are within range of array.
            if (rowStart < 0 || columnStart < 0 || rowStart > array.GetU
pperBound(0) || columnStart > array.GetUpperBound(1) ||
                rowCount < 1 || rowCount + rowStart - 1 > array.GetUpper
Bound(0) || columnCount < 1 || columnCount + columnStart - 1 > array.Get
UpperBound(1))
                throw new System.IndexOutOfRangeException("Start or end
values out of range (ToArray)");

            //Put 2D array values in a 1D array
            T[] array1d = new T[rowCount * columnCount];
            int currentRow = -1;
            for (int row = rowStart; row < rowCount + rowStart; row++)
            {
                for (int column = columnStart; column < columnCount + co
lumnStart; column++)
                {
                    currentRow += 1;
                    array1d[currentRow] = conversion(array[row, column])
;
                }
            }

            return array1d;

        } //End ToArray

        /// <summary>
        /// Copies the elements of the 2D object array row wise to a new
 array of the specified element type and length.
        /// </summary>
        /// <typeparam name="T">New array type.</typeparam>
        /// <param name="array">The two-dimensional object array.</param
>
        /// <param name="conversion">Casting function of new type.</para
m>
        /// <returns>One-dimensional array of type TSource</returns>
        /// <remarks> Jon Nyman 20130205
        /// Source http://msmvps.com/blogs/jon_skeet/archive/2011/01/02/
reimplementing-linq-to-objects-part-24-toarray.aspx </remarks>
        public static T[] ToArray<T>(this object[,] array, Func<object,
T> conversion)
        {
            int rowStart=array.GetLowerBound(0);
            int colStart=array.GetLowerBound(1);
            int rowCount=array.GetUpperBound(0)-rowStart+1;
            int colCount=array.GetUpperBound(1)-colStart+1;

            return array.ToArray<T>(conversion, rowStart, colStart, rowC
ount, colCount);

        } //End ToArray

        /// <summary>
        /// Create 2D object array from enumerable type.
        /// </summary>
        /// <typeparam name="TSource">Enumerable type to convert.</typep
aram>
        /// <param name="enumerator">Enumerable to convert.</param>
        /// <param name="conversion">Logic to convert to object array.</
param>
        /// <param name="startIndex">First index to start.</param>
        /// <param name="count">Number to convert.</param>
        /// <param name="columnCount">Number of columns to create.</para
m>
        /// <example>If clsItems.Count > 0 Then
        ///           oaTimes = clsItems.Compose(Function(cls) _
        ///                {CType(clsItems.DateUsed.ToOADate, Object) _
        ///                 , cls.Name _
        ///                 , cls.ItemHoursForDay _
        ///                 , cls.ClockInTime}, 4)
        ///End If</example>
        /// <returns>2D Object Array</returns>
        /// <remarks>Jon Nyman 121109</remarks>
        public static object[,] Compose<TSource>(this IEnumerable<TSourc
e> enumerator, Func<TSource, object[]> conversion

,  int columnCount)
        {
            try
            {
                int count = enumerator.Count();
                int row = -1;
                object[,] array2d = new object[count, columnCount];

                foreach (TSource item in enumerator)
                {
                    row += 1;
                    object[] array = new object[columnCount];
                    array = conversion(item);
                    for (int j = 0; j <= columnCount - 1; j++)
                    {
                        array2d[row, j] = array[j];
                    }
                }

                return array2d;

            }
            catch (System.IndexOutOfRangeException)
            {
                throw new System.IndexOutOfRangeException("Incorrect num
ber of columns. Compose.");
            }

        } //End Compose

    }
}