How to make an alocation free from Span<char> to a char[] - c#

I've been trying to generate a alocation free from a struct in c#
Basically I create my on struct that recives an string (ReadOnlySpan) that could have any size like 'ABC1234.5GDS' and then inside of the constructor of that struct I create a Span stackalloc char[5] then I interate on ReadOnlySpan getting only the 5 first numbers at the end my Span has the '12345' on it but how do I pin that address to a char[] so I can use that later.
Basically I want to do the same as DateTime that you can be allocation free until you call ToString()
public readonly struct AllocFree
{
private readonly char[] data;
public AllocFree(ReadOnlySpan<char> input)
{
int position = 0;
Span<char> newData = stackalloc char[5];
for (int i = 0; i < input.Length; i++)
{
if (char.IsDigit(input[i]))
{
newData[position] = input[i];
position++;
}
if (position == 4)
break;
}
// How to make this a allocation free.
data = newData;
// This is a no allocation free.
data = newData.ToArray();
}
public override string ToString() => new String(data);
}

Related

How do i create a struct in C# that contains an array but does not use heap?

What i need:
a polygon with arbitrary amount of vertices ( or at least up to max number of vertices )
it should be a struct, so that it can be fast and can be assigned / passed by value
It seems like i can't use arrays or collections for storing vertices, because then my polygon struct would point to objects on a heap, and when one polygon is assigned to another one by value only shallow copy would be performed, and i would have both polygons pointing to the same vertex array. For example:
Polygon a = new Polygon();
Polygon b = a;
// both polygons would be changed
b.vertices[0] = 5;
Then how do i create a struct that can have arbitrary number (or some fixed number) of vertices, but without using heap at all?
I could just use lots of variables like v1, v2, v3 ... v10 etc, but i want to keep my code clean, more or less.
You have the option to define your array with the fixed keyword, which puts it in the stack.
But you cannot directly access the elements of the array, unless you are in an unsafe context and use pointers.
To get the following behavior:
static void Main(string[] args)
{
FixedArray vertices = new FixedArray(10);
vertices[0] = 4;
FixedArray copy = vertices;
copy[0] = 8;
Debug.WriteLine(vertices[0]);
// 4
Debug.WriteLine(copy[0]);
// 8
}
Then use the following class definition:
public unsafe struct FixedArray
{
public const int MaxSize = 100;
readonly int size;
fixed double data[MaxSize];
public FixedArray(int size) : this(new double[size])
{ }
public FixedArray(double[] values)
{
this.size = Math.Min(values.Length, MaxSize);
for (int i = 0; i < size; i++)
{
data[i] = values[i];
}
}
public double this[int index]
{
get
{
if (index>=0 && index<size)
{
return data[index];
}
return 0;
}
set
{
if (index>=0 && index<size)
{
data[index] = value;
}
}
}
public double[] ToArray()
{
var array = new double[size];
for (int i = 0; i < size; i++)
{
array[i] = data[i];
}
return array;
}
}
A couple of things to consider. The above needs to be compiled with the unsafe option. Also the MaxSize but be a constant, and the storage required cannot exceed this value. I am using an indexer this[int] to access the elements (instead of a field) and also have a method to convert to a native array with ToArray(). The constructor can also take a native array, or it will use an empty array to initialize the values. This is to ensure that new FixedArray(10) for example will have initialized at least 10 values in the fixed array (instead of being undefined as it is the default).
Read more about this usage of fixed from Microsoft or search for C# Fixed Size Buffers.
Heap array field
struct StdArray
{
int[] vertices;
Foo(int size)
{
vertices = new int[size];
}
}
Stack array field
unsafe struct FixedArray
{
fixed int vertices[100];
int size;
Foo(int size)
{
this.size = size;
// no initialization needed for `vertices`
}
}
If it suits your logic, you could use a Span<T>, which is allocated on the stack. Read more here
One other way to just copy the array with a copy constructor
public Polygon(Polygon other)
{
this.vertices = other.vertices.Clone() as int[];
}
then
var a = new Polygon();
a.vertices[0] = 5;
var b = new Polygon(a):
Debug.WriteLine(a.vertices[0]);
// 5
Debug.WriteLine(b.vertices[0]);
// 5
b.vertices[0] = 10;
Debug.WriteLine(a.vertices[0]);
// 5
Debug.WriteLine(b.vertices[0]);
// 10

Time-complexity of looking at item in stringbuider - C#

I have some long text saved in StringBuilder and I want to get some specific item
StringBuilder builder = new StringBuilder();
//fill builder
int i = someNumber();
char ch = builder[i];
what is the time-complexity of the last instruction (char ch = builder[i])? Is it constant
O(1)
or is it linear?
O(i)
As per Reference Source the StringBuilder class stores strings in a char Array.
Accessing this array via the property getter this[int index] does a few checks and then returns the array item:
internal char[] m_ChunkChars; // The characters in this block
//...more stuff
[System.Runtime.CompilerServices.IndexerName("Chars")]
public char this[int index] {
//
get {
StringBuilder chunk = this;
for (; ; )
{
int indexInBlock = index - chunk.m_ChunkOffset;
if (indexInBlock >= 0)
{
if (indexInBlock >= chunk.m_ChunkLength)
throw new IndexOutOfRangeException();
return chunk.m_ChunkChars[indexInBlock];
}
chunk = chunk.m_ChunkPrevious;
if (chunk == null)
throw new IndexOutOfRangeException();
}
}
//... more stuff
}
Thus the complexity is O(1) or constant access time.
It is a constant as you are giving exact location to get the element.So in this case O(1). More details here
What is the complexity of this simple piece of code?
char ch = builder[i] is O(1) .
Because StringBuilder used array index.
Looking at the implementation of StringBuilder, it is O(1) because is use char[]
//
//
// CLASS VARIABLES
//
//
internal char[] m_ChunkChars; // The characters in this block
internal StringBuilder m_ChunkPrevious; // Link to the block logically before this block
internal int m_ChunkLength; // The index in m_ChunkChars that represent the end of the block
internal int m_ChunkOffset; // The logial offset (sum of all characters in previous blocks)
internal int m_MaxCapacity = 0;

having issues when extracting char values, using unsafe char* in a struct []

in this code i am trying to simulate a task that populats an array of structs,
...unsafe to get as much throughoutput as can be achived.
the issue is that i when calling the fucntion and itterating on the result
shows different characters but within the scope of GetSomeTs() it's fine.
so just before the return i test one of the elements and it prints the correct value.
this is the testing struct.
public unsafe struct T1
{
public char* block = stackalloc char[5];<--will not compile so the process will be done within a local variable inside a method
}
public unsafe struct T1
{
public char* block;
}
static unsafe T1[] GetSomeTs(int ArrSz)
{
char[] SomeValChars = { 'a', 'b', 'c', 'd', 'e' };
T1[] RtT1Arr = new T1[ArrSz];
for (int i = 0; i < RtT1Arr.Length; i++)
{
char* tmpCap = stackalloc char[5];
for (int l = 0; l < 5; l++)
{
SomeValChars[4] = i.ToString()[0];
tmpCap[l] = SomeValChars[l];
}
RtT1Arr[i].block = tmpCap;//try 1
//arr[i].block = &tmpCap[0];//try 2
}
// here its fine
Console.WriteLine("{0}", new string(RtT1Arr[1].block));
return RtT1Arr;
}
but using it anywhere else printing garbage.
void Main()
{
T1[] tstT1 = GetSomeTs(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("{0}", new string(tstT1[i].block));//,0,5, Encoding.Default));
}
}
When you allocate memory with stackalloc that memory only exists until the function returns in which you have allocated it. You are returning a pointer to memory that is no longer allowed to be accessed.
Hard to recommend a fix because it's unclear what you want to achieve. Probably, you should just use a managed char[].
Encoding.Default.GetBytes is pretty slow so that's likely to be your hotspot anyway and the rest is less important. i.ToString() also is quite slow and produces garbage. If you are after perf then stop creating unneeded objects all the time such as SomeValChars. Create it once and reuse.

Array of array initialization by using unmanaged pointers in C#

I would like to define an array of array eg int[][] on top of an existing int[] of the right size. I want then to seamlessy use either the int[][] array of array or the int[] 'big' array while refering to the same inner data.
Is this possible to do this in C# using unmanaged code? In C++ I would defined pointers like this :
int* bigArray = new int[numberOfRows * numberOfColumns];
int** matrix = new int*[numberOfRows];
for (int i = 0; i < numberOfRows; i ++)
{
matrix[i] = (bigArray + i * numberOfColumns);
}
Yes, you can also use pointer in C#, but there are some limits on it. 1st, you need to declare the function with unsafe, and also, you need to set the build option to allow unsafe code in the project property, here is the sample code about it:
unsafe static void T1(int numberOfRows, int numberOfColumns)
{
int* bigArray = stackalloc int[numberOfRows * numberOfColumns];
int** matrix = stackalloc int*[numberOfRows];
for (int i = 0; i < numberOfRows; i++)
{
matrix[i] = (bigArray + i * numberOfColumns);
}
}
Remember, you can use the pointer only if you are so clear of that you have full control of your code. while it is not recommend you use the pointer in C#
You can do it in managed code, using a class as a wrapper and providing it with an indexer:
class Matrix
{
public readonly int[] BigArray; // make available
private int _rowSize = ...;
public int this[int x, int y]
{
get { return BigArray [x*_rowSize+y]; }
set { BigArray [x*_rowSize+y] = value; }
}
}
Edit:
changed arrray into public readonly field so that the class has a dual interface
Edit 2:
Using T[][] to provide access to T[] rows.
class Matrix2<T>
{
private T[][] _data;
private int _columns;
public Matrix2(int rows, int cols)
{
_data = new T[rows][];
_columns = cols;
for (int i = 0; i < rows; i++) _data[i] = new T[cols];
}
public T this [int x]
{
get { return _data [x/_columns][x % _columns]; }
set { _data [x/_columns][x % _columns] = value; }
}
public T[] Row(int r)
{
return _data [r];
}
}

How do I clone a range of array elements to a new array?

I have an array X of 10 elements. I would like to create a new array containing all the elements from X that begin at index 3 and ends in index 7. Sure I can easily write a loop that will do it for me but I would like to keep my code as clean as possible. Is there a method in C# that can do it for me?
Something like (pseudo code):
Array NewArray = oldArray.createNewArrayFromRange(int BeginIndex , int EndIndex)
Array.Copy doesn't fit my needs. I need the items in the new array to be clones. Array.copy is just a C-Style memcpy equivalent, it's not what I'm looking for.
You could add it as an extension method:
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
static void Main()
{
int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] sub = data.SubArray(3, 4); // contains {3,4,5,6}
}
Update re cloning (which wasn't obvious in the original question). If you really want a deep clone; something like:
public static T[] SubArrayDeepClone<T>(this T[] data, int index, int length)
{
T[] arrCopy = new T[length];
Array.Copy(data, index, arrCopy, 0, length);
using (MemoryStream ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, arrCopy);
ms.Position = 0;
return (T[])bf.Deserialize(ms);
}
}
This does require the objects to be serializable ([Serializable] or ISerializable), though. You could easily substitute for any other serializer as appropriate - XmlSerializer, DataContractSerializer, protobuf-net, etc.
Note that deep clone is tricky without serialization; in particular, ICloneable is hard to trust in most cases.
You can use Array.Copy(...) to copy into the new array after you've created it, but I don't think there's a method which creates the new array and copies a range of elements.
If you're using .NET 3.5 you could use LINQ:
var newArray = array.Skip(3).Take(5).ToArray();
but that will be somewhat less efficient.
See this answer to a similar question for options for more specific situations.
Have you considered using ArraySegment?
http://msdn.microsoft.com/en-us/library/1hsbd92d.aspx
I see you want to do Cloning, not just copying references.
In this case you can use .Select to project array members to their clones.
For example, if your elements implemented IClonable you could do something like this:
var newArray = array.Skip(3).Take(5).Select(eachElement => eachElement.Clone()).ToArray();
Note: This solution requires .NET Framework 3.5.
The following code does it in one line:
// Source array
string[] Source = new string[] { "A", "B", "C", "D" };
// Extracting a slice into another array
string[] Slice = new List<string>(Source).GetRange(2, 2).ToArray();
In C# 8, they've introduced a new Range and Index type, which can be used like this:
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Index i1 = 3; // number 3 from beginning
Index i2 = ^4; // number 4 from end
var slice = a[i1..i2]; // { 3, 4, 5 }
References:
https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#ranges-and-indices
https://devblogs.microsoft.com/dotnet/building-c-8-0/
string[] arr = { "Parrot" , "Snake" ,"Rabbit" , "Dog" , "cat" };
arr = arr.ToList().GetRange(0, arr.Length -1).ToArray();
Building on Marc's answer but adding the desired cloning behaviour
public static T[] CloneSubArray<T>(this T[] data, int index, int length)
where T : ICloneable
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Clone();
return result;
}
And if implementing ICloneable is too much like hard work a reflective one using Håvard Stranden’s Copyable library to do the heavy lifting required.
using OX.Copyable;
public static T[] DeepCopySubArray<T>(
this T[] data, int index, int length)
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Copy();
return result;
}
Note that the OX.Copyable implementation works with any of:
For the automated copy to work, though, one of the following statements must hold for instance:
Its type must have a parameterless constructor, or
It must be a Copyable, or
It must have an IInstanceProvider registered for its type.
So this should cover almost any situation you have. If you are cloning objects where the sub graph contains things like db connections or file/stream handles you obviously have issues but that it true for any generalized deep copy.
If you want to use some other deep copy approach instead this article lists several others so I would suggest not trying to write your own.
You can do this fairly easially;
object[] foo = new object[10];
object[] bar = new object[7];
Array.Copy(foo, 3, bar, 0, 7);
I think that the code you are looking for is:
Array.Copy(oldArray, 0, newArray, BeginIndex, EndIndex - BeginIndex)
As an alternative to copying the data you can make a wrapper that gives you access to a part of the original array as if it was a copy of the part of the array. The advantage is that you don't get another copy of the data in memory, and the drawback is a slight overhead when accessing the data.
public class SubArray<T> : IEnumerable<T> {
private T[] _original;
private int _start;
public SubArray(T[] original, int start, int len) {
_original = original;
_start = start;
Length = len;
}
public T this[int index] {
get {
if (index < 0 || index >= Length) throw new IndexOutOfRangeException();
return _original[_start + index];
}
}
public int Length { get; private set; }
public IEnumerator<T> GetEnumerator() {
for (int i = 0; i < Length; i++) {
yield return _original[_start + i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
Usage:
int[] original = { 1, 2, 3, 4, 5 };
SubArray<int> copy = new SubArray<int>(original, 2, 2);
Console.WriteLine(copy.Length); // shows: 2
Console.WriteLine(copy[0]); // shows: 3
foreach (int i in copy) Console.WriteLine(i); // shows 3 and 4
In C# 8.0, you can now do many fancier works including reverse indices and ranges like in Python, such as:
int[] list = {1, 2, 3, 4, 5, 6};
var list2 = list[2..5].Clone() as int[]; // 3, 4, 5
var list3 = list[..5].Clone() as int[]; // 1, 2, 3, 4, 5
var list4 = list[^4..^0].Clone() as int[]; // reverse index
Array.ConstrainedCopy will work.
public static void ConstrainedCopy (
Array sourceArray,
int sourceIndex,
Array destinationArray,
int destinationIndex,
int length
)
It does not meet your cloning requirement, but it seems simpler than many answers to do:
Array NewArray = new ArraySegment(oldArray,BeginIndex , int Count).ToArray();
There's no single method that will do what you want. You will need to make a clone method available for the class in your array. Then, if LINQ is an option:
Foo[] newArray = oldArray.Skip(3).Take(5).Select(item => item.Clone()).ToArray();
class Foo
{
public Foo Clone()
{
return (Foo)MemberwiseClone();
}
}
How about useing Array.ConstrainedCopy:
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
Array.ConstrainedCopy(ArrayOne, 3, ArrayTwo, 0, 7-3);
Below is my original post. It will not work
You could use Array.CopyTo:
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
ArrayOne.CopyTo(ArrayTwo,3); //starts copy at index=3 until it reaches end of
//either array
How about this:
public T[] CloneCopy(T[] array, int startIndex, int endIndex) where T : ICloneable
{
T[] retArray = new T[endIndex - startIndex];
for (int i = startIndex; i < endIndex; i++)
{
array[i - startIndex] = array[i].Clone();
}
return retArray;
}
You then need to implement the ICloneable interface on all of the classes you need to use this on but that should do it.
I'm not sure how deep it really is, but:
MyArray.ToList<TSource>().GetRange(beginningIndex, endIndex).ToArray()
It's a bit of overhead, but it might cut out an unnecessary method.
As far as cloning goes, I don't think serialization calls your constructors. This may break class invariants if you're doing interesting things in the ctor's.
It seems the safer bet is virtual clone methods calling copy constructors.
protected MyDerivedClass(MyDerivedClass myClass)
{
...
}
public override MyBaseClass Clone()
{
return new MyDerivedClass(this);
}
Cloning elements in an array is not something that can be done in a universal way. Do you want deep cloning or a simple copy of all members?
Let's go for the "best effort" approach: cloning objects using the ICloneable interface or binary serialization:
public static class ArrayExtensions
{
public static T[] SubArray<T>(this T[] array, int index, int length)
{
T[] result = new T[length];
for (int i=index;i<length+index && i<array.Length;i++)
{
if (array[i] is ICloneable)
result[i-index] = (T) ((ICloneable)array[i]).Clone();
else
result[i-index] = (T) CloneObject(array[i]);
}
return result;
}
private static object CloneObject(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
stream.Seek(0,SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
}
This is not a perfect solution, because there simply is none that will work for any type of object.
You can take class made by Microsoft:
internal class Set<TElement>
{
private int[] _buckets;
private Slot[] _slots;
private int _count;
private int _freeList;
private readonly IEqualityComparer<TElement> _comparer;
public Set()
: this(null)
{
}
public Set(IEqualityComparer<TElement> comparer)
{
if (comparer == null)
comparer = EqualityComparer<TElement>.Default;
_comparer = comparer;
_buckets = new int[7];
_slots = new Slot[7];
_freeList = -1;
}
public bool Add(TElement value)
{
return !Find(value, true);
}
public bool Contains(TElement value)
{
return Find(value, false);
}
public bool Remove(TElement value)
{
var hashCode = InternalGetHashCode(value);
var index1 = hashCode % _buckets.Length;
var index2 = -1;
for (var index3 = _buckets[index1] - 1; index3 >= 0; index3 = _slots[index3].Next)
{
if (_slots[index3].HashCode == hashCode && _comparer.Equals(_slots[index3].Value, value))
{
if (index2 < 0)
_buckets[index1] = _slots[index3].Next + 1;
else
_slots[index2].Next = _slots[index3].Next;
_slots[index3].HashCode = -1;
_slots[index3].Value = default(TElement);
_slots[index3].Next = _freeList;
_freeList = index3;
return true;
}
index2 = index3;
}
return false;
}
private bool Find(TElement value, bool add)
{
var hashCode = InternalGetHashCode(value);
for (var index = _buckets[hashCode % _buckets.Length] - 1; index >= 0; index = _slots[index].Next)
{
if (_slots[index].HashCode == hashCode && _comparer.Equals(_slots[index].Value, value))
return true;
}
if (add)
{
int index1;
if (_freeList >= 0)
{
index1 = _freeList;
_freeList = _slots[index1].Next;
}
else
{
if (_count == _slots.Length)
Resize();
index1 = _count;
++_count;
}
int index2 = hashCode % _buckets.Length;
_slots[index1].HashCode = hashCode;
_slots[index1].Value = value;
_slots[index1].Next = _buckets[index2] - 1;
_buckets[index2] = index1 + 1;
}
return false;
}
private void Resize()
{
var length = checked(_count * 2 + 1);
var numArray = new int[length];
var slotArray = new Slot[length];
Array.Copy(_slots, 0, slotArray, 0, _count);
for (var index1 = 0; index1 < _count; ++index1)
{
int index2 = slotArray[index1].HashCode % length;
slotArray[index1].Next = numArray[index2] - 1;
numArray[index2] = index1 + 1;
}
_buckets = numArray;
_slots = slotArray;
}
internal int InternalGetHashCode(TElement value)
{
if (value != null)
return _comparer.GetHashCode(value) & int.MaxValue;
return 0;
}
internal struct Slot
{
internal int HashCode;
internal TElement Value;
internal int Next;
}
}
and then
public static T[] GetSub<T>(this T[] first, T[] second)
{
var items = IntersectIteratorWithIndex(first, second);
if (!items.Any()) return new T[] { };
var index = items.First().Item2;
var length = first.Count() - index;
var subArray = new T[length];
Array.Copy(first, index, subArray, 0, length);
return subArray;
}
private static IEnumerable<Tuple<T, Int32>> IntersectIteratorWithIndex<T>(IEnumerable<T> first, IEnumerable<T> second)
{
var firstList = first.ToList();
var set = new Set<T>();
foreach (var i in second)
set.Add(i);
foreach (var i in firstList)
{
if (set.Remove(i))
yield return new Tuple<T, Int32>(i, firstList.IndexOf(i));
}
}
This is the optimal way, I found, to do this:
private void GetSubArrayThroughArraySegment() {
int[] array = { 10, 20, 30 };
ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2);
Console.WriteLine("-- Array --");
int[] original = segment.Array;
foreach (int value in original)
{
Console.WriteLine(value);
}
Console.WriteLine("-- Offset --");
Console.WriteLine(segment.Offset);
Console.WriteLine("-- Count --");
Console.WriteLine(segment.Count);
Console.WriteLine("-- Range --");
for (int i = segment.Offset; i <= segment.Count; i++)
{
Console.WriteLine(segment.Array[i]);
}
}
Hope It Helps!
use extention method :
public static T[] Slice<T>(this T[] source, int start, int end)
{
// Handles negative ends.
if (end < 0)
{
end = source.Length + end;
}
int len = end - start;
// Return new array.
T[] res = new T[len];
for (int i = 0; i < len; i++)
{
res[i] = source[i + start];
}
return res;
}
and you can use it
var NewArray = OldArray.Slice(3,7);
Code from the System.Private.CoreLib.dll:
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
(int Offset, int Length) offsetAndLength = range.GetOffsetAndLength(array.Length);
int item = offsetAndLength.Offset;
int item2 = offsetAndLength.Length;
if (default(T) != null || typeof(T[]) == array.GetType())
{
if (item2 == 0)
{
return Array.Empty<T>();
}
T[] array2 = new T[item2];
Buffer.Memmove(ref Unsafe.As<byte, T>(ref array2.GetRawSzArrayData()), ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), item), (uint)item2);
return array2;
}
T[] array3 = (T[])Array.CreateInstance(array.GetType().GetElementType(), item2);
Array.Copy(array, item, array3, 0, item2);
return array3;
}
array1 = [5,6,7,8];
int[] array2 = new int[2];
Array.ConstrainedCopy(array1, 1, array2, 0, 2);
array2 = [6,7];
Array.ConstrainedCopy takes five (5) parameters:
source array (sourceArray)
starting index of source array (sourceIndex)
destination array (destinationArray)
starting index of destination array (destinationIndex)
number of elements to copy (length)
public static T[] SubArray<T>(T[] data, int index, int length)
{
List<T> retVal = new List<T>();
if (data == null || data.Length == 0)
return retVal.ToArray();
bool startRead = false;
int count = 0;
for (int i = 0; i < data.Length; i++)
{
if (i == index && !startRead)
startRead = true;
if (startRead)
{
retVal.Add(data[i]);
count++;
if (count == length)
break;
}
}
return retVal.ToArray();
}

Categories

Resources