Between .NET's built-in collection libraries and LINQ extension methods, I never have to use arrays. An unfortunate consequence of this is that I am probably less competent in working with this very important Type than I should be. To help myself get a better grip on the Array
class, I wrote some C# helper methods that mimic the "Mutator" methods in the JavaScript array type. These methods are documented thoroughly at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array . I omitted the methods that already have analogous implementations in .NET, (including reverse
and sort
). I also tried to avoid using LINQ, on which I have grown pretty dependent. (LINQ also manipulates arrays under the hood, so a properly written direct approach should perform better).
I appreciate : (1) any feedback and/or highlighting of anywhere I may have messed up, (2) highlighting of any errors that may not necessarily but could potentially cause problems (such as thread-safety issues); (3) any optimization techniques that I should have used; and, (4) anything I did that was generally stupid.
I use an IsNullOrEmpty
extension method that is equivalent to ReferenceEquals(array,null) || array.Length == 0
public static class ArrayMutator
{
public static T Pop<T>(ref T[] array)
{
Contract.Requires<ArgumentException>(!array.IsNullOrEmpty());
T result = array[array.Length - 1];
if (array.Length == 1)
{
array = new T[0];
}
else
{
var popped = new T[array.Length - 1];
System.Array.Copy(array, 0, popped, 0, array.Length - 1);
array = popped;
}
return result;
}
public static int Push<T>(ref T[] array, T element)
{
if (array.IsNullOrEmpty())
{
array = new T[1] {element};
return 1;
}
var pushed = new T[array.Length + 1];
array.CopyTo(pushed, 0);
pushed[array.Length] = element;
array = pushed;
return pushed.Length;
}
public static int Push<T>(ref T[] array, params T[] elements)
{
if (array.IsNullOrEmpty())
{
if (elements.IsNullOrEmpty())
{
array = new T[0];
return 0;
}
else
{
var elementsCopy = new T[elements.Length];
elements.CopyTo(elementsCopy, 0);
array = elementsCopy;
return elementsCopy.Length;
}
}
if (elements.IsNullOrEmpty())
{
return array.Length;
}
int total = array.Length + elements.Length;
var pushed = new T[total];
array.CopyTo(pushed, 0);
elements.CopyTo(pushed, array.Length);
array = pushed;
return total;
}
public static T Shift<T>(ref T[] array)
{
Contract.Requires<ArgumentException>(!array.IsNullOrEmpty());
T result = array[0];
if (array.Length == 1)
{
array = new T[0];
}
else
{
var shifted = new T[array.Length - 1];
System.Array.Copy(array, 1, shifted, 0, array.Length - 1);
array = shifted;
}
return result;
}
public static T[] Splice<T>(ref T[] array, int index, int removeCount, params T[] elements)
{
Contract.Requires<ArgumentNullException>(!ReferenceEquals(array, null));
Contract.Requires<ArgumentOutOfRangeException>(array.Length > Math.Abs(index) ||
(array.Length == 0 && index == 0));
Contract.Requires<ArgumentOutOfRangeException>(removeCount >= 0 &&
(Math.Abs(index) + removeCount) < array.Length);
T[] local = array;
int addCount = ReferenceEquals(elements, null) ? 0 : elements.Length;
if (index < 0) index = local.Length - index;
var spliced = new T[local.Length - removeCount + addCount];
var removed = new T[removeCount];
if (index == 0)
{
if (removeCount == 0)
{
local.CopyTo(spliced, 0);
if (addCount > 0)
{
elements.CopyTo(spliced, local.Length);
}
}
else
{
System.Array.Copy(local, removeCount, spliced, 0, local.Length - removeCount);
if (addCount > 0)
{
elements.CopyTo(spliced, local.Length - removeCount);
}
}
}
else
{
if (removeCount == 0 && addCount == 0)
local.CopyTo(spliced, 0);
else
{
System.Array.Copy(
local,
0,
spliced,
0,
index + 1);
if (addCount > 0)
{
elements.CopyTo(spliced, index);
}
System.Array.Copy(
local,
index + removeCount,
spliced,
index + addCount,
local.Length - index - removeCount
);
}
}
array = local;
return removed;
}
public static int Unshift<T>(ref T[] array, T element)
{
if (array.IsNullOrEmpty())
{
array = new T[1] {element};
return 1;
}
var unshifted = new T[array.Length + 1];
unshifted[0] = element;
array.CopyTo(unshifted, 1);
array = unshifted;
return unshifted.Length;
}
public static int Unshift<T>(ref T[] array, params T[] elements)
{
if (array.IsNullOrEmpty())
{
if (elements.IsNullOrEmpty())
{
array = new T[0];
return 0;
}
else
{
var elementsCopy = new T[elements.Length];
elements.CopyTo(elementsCopy, 0);
array = elementsCopy;
return elementsCopy.Length;
}
}
if (elements.IsNullOrEmpty())
{
return array.Length;
}
int total = array.Length + elements.Length;
var unshifted = new T[total];
elements.CopyTo(unshifted, 0);
array.CopyTo(unshifted, elements.Length);
array = unshifted;
return total;
}
}
Revisions
- Replaced all occurrences of
Array.ConstrainedCopy
withArray.Copy
, thanks to @svick's suggestion