Skip to content

Instantly share code, notes, and snippets.

@Virtlink
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Virtlink/9063619 to your computer and use it in GitHub Desktop.
Save Virtlink/9063619 to your computer and use it in GitHub Desktop.
Helper methods for creating nested arrays.
using System;
using System.Diagnostics;
using System.Linq;
namespace Virtlink
{
/// <summary>
/// Helper methods for creating nested arrays.
/// </summary>
/// <example>
/// Usage example:
/// <code>
/// int[][][] myArray = (int[][][])NestedArray.Create&lt;int&gt;(10, 5, 3);
/// </code>
/// </example>
/// <remarks>
/// Created by Virtlink. Original source code on GitHub:
/// <see href="https://gist.github.com/Virtlink/9063619"/>.
/// </remarks>
public static class NestedArray
{
/// <summary>
/// Creates a nested array.
/// </summary>
/// <typeparam name="T">The type of elements in the most nested array.</typeparam>
/// <param name="lengths">The length of each level of the nested arrays.</param>
/// <returns>The created <see cref="Array"/> object.</returns>
public static Array Create<T>(params int[] lengths)
{
#region Contract
if (lengths == null) throw new ArgumentNullException("lengths");
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths");
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative.");
#endregion
return Create(typeof(T), lengths);
}
/// <summary>
/// Creates a nested array.
/// </summary>
/// <typeparam name="T">The type of elements in the most nested array.</typeparam>
/// <param name="lengths">The length of each level of the nested arrays.</param>
/// <param name="defaultValue">The default value of the most nested elements.</param>
/// <returns>The created <see cref="Array"/> object.</returns>
public static Array Create<T>(int[] lengths, T defaultValue)
{
#region Contract
if (lengths == null) throw new ArgumentNullException("lengths");
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths");
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative.");
#endregion
return Create(typeof(T), lengths, (object)defaultValue);
}
/// <summary>
/// Creates a nested array.
/// </summary>
/// <param name="elementType">The type of elements in the most nested array.</param>
/// <param name="lengths">The length of each level of the nested arrays.</param>
/// <returns>The created <see cref="Array"/> object.</returns>
public static Array Create(Type elementType, params int[] lengths)
{
#region Contract
if (elementType == null) throw new ArgumentNullException("elementType");
if (lengths == null) throw new ArgumentNullException("lengths");
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths");
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative.");
#endregion
return Create(elementType, lengths, null);
}
/// <summary>
/// Creates a nested array.
/// </summary>
/// <param name="elementType">The type of elements in the most nested array.</param>
/// <param name="lengths">The length of each level of the nested arrays.</param>
/// <param name="defaultValue">The default value of the most nested elements.</param>
/// <returns>The created <see cref="Array"/> object.</returns>
public static Array Create(Type elementType, int[] lengths, object defaultValue)
{
#region Contract
if (elementType == null) throw new ArgumentNullException("elementType");
if (lengths == null) throw new ArgumentNullException("lengths");
if (lengths.Length == 0) throw new ArgumentException("Specify at least one length.", "lengths");
if (lengths.Any(v => v < 0)) throw new ArgumentOutOfRangeException("lengths", "The lengths may not be negative.");
#endregion
// Get the Type of the sub array, e.g. int[][] if there are three lengths specified.
Type arrayType = elementType;
for (int i = 0; i < lengths.Length - 1; i++)
{
arrayType = arrayType.MakeArrayType();
}
// Recursively create the sub arrays.
return CreateArray(arrayType, defaultValue, lengths[0], lengths.Skip(1).ToArray());
}
/// <summary>
/// Create an array.
/// </summary>
/// <param name="elementType">The type of elements in the array.</param>
/// <param name="defaultValue">The default value of the most nested elements;
/// or <see langword="null"/> to specify none.</param>
/// <param name="length">The length of the array.</param>
/// <param name="subLengths">The lengths of the arrays nested in the array.</param>
/// <returns>The array, with all nested arrays initialzed to their default values.</returns>
private static Array CreateArray(Type elementType, object defaultValue, int length, int[] subLengths)
{
#region Contract
Debug.Assert(elementType != null);
Debug.Assert(length >= 0);
Debug.Assert(subLengths != null);
#endregion
// Create the array.
Array array = Array.CreateInstance(elementType, length);
// If this array has any sub arrays, create them too.
if (subLengths.Length > 0)
{
for (int i = 0; i < length; i++)
{
Array nestedArray = CreateArray(elementType.GetElementType(), defaultValue, subLengths[0], subLengths.Skip(1).ToArray());
array.SetValue(nestedArray, i);
}
}
else if (defaultValue != null)
{
for (int i = 0; i < length; i++)
{
array.SetValue(defaultValue, i);
}
}
return array;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment