How to dynamically resize an array? - c#

I have an array with Length = 3 and with values, for example {1,2,3}.
I need to dynamically resize it.
I know that I can use List or
Array.Resize(). But I need to know how to implement my own resize method?

You can try the following code. Create new array with new size and copy the old array data to the newly created array.
public static Array ResizeArray (Array oldArray, int newSize)
{
int oldSize = oldArray.Length;
Type elementType = oldArray.GetType().GetElementType();
Array newArray = Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
{
Array.Copy (oldArray,newArray,preserveLength);
}
return newArray;
}

If this is just for practice then do it. but i suggest you use .Net Array.Resize() if you want to use it in your code. usually .Net libraries are best implemented and optimized.
Any way...you can do it with generic method
private static void Resize<T>(ref T[] array,int size)
{
T[] token = array.Take(size).ToArray(); // attempt to take first n elements
T[] temp = new T[size]; // create new reference
token.CopyTo(temp, 0); // copy array contents to new array
array = temp; // change reference
}
Note that you cannot do this without parameter ref. (The other way is to return array of course)
You may think arrays are passed by reference. thats true. But the references it self are passed by value. so whenever you try to change the reference it does not refer to the original array anymore. you can only change the contents. To make this possible you have to use ref to directly pass the reference into method.
About the code:
{1,2,3} if you resize it to 2 obviously it will remove the last parameter. so you will have {1,2}
if you resize it to 4 then it will give the array with new default values. either null for reference types or 0 for value types (false for Boolean type). here you will have {1,2,3,0}
int[] array = new[] {1, 2, 3};
Resize(ref array,4);
Console.WriteLine(array.Length); // outputs 4

Well, you may look on Array.Resize source code before making your own implementation =)
http://referencesource.microsoft.com/#mscorlib/system/array.cs,71074deaf111c4e3

If you want to resize the array use the build in method Array.Resize().It will be easier and faster.
If you need a dynamically sized data structure, use List for that.
You can always do array.ToList() -> fill the list and do .ToArray() later.

Make an array of the new desired size, copy all items over. Make the variable that referenced your old array reference the new one.
Code from MSDN:
public static void Resize<T>(ref T[] array, int newSize) {
if (newSize < 0) {
throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.Ensures(Contract.ValueAtReturn(out array) != null);
Contract.Ensures(Contract.ValueAtReturn(out array).Length == newSize);
Contract.EndContractBlock();
T[] larray = array;
if (larray == null) {
array = new T[newSize];
return;
}
if (larray.Length != newSize) {
T[] newArray = new T[newSize];
Array.Copy(larray, 0, newArray, 0, larray.Length > newSize? newSize : larray.Length);
array = newArray;
}
}
}

Related

Can arrays be resized in C#

Just out of curiosity, coming from C background, I knew that Array cannot be resized.
However, while I see in C#, it's so easy to do like below
var arr = new int[] {1,2,4,6};
arr = new int[2];
Also, there is a method available
Array.Resize(ref arr, 10);
How is it possible?
Thanks!
These operations aren't resizing the array. They're creating a new array of a new size.
Note in the first example that you call new twice. So you're creating two arrays.
In the second example, the documentation explains the same:
This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.
The source code for the Array class can be found here.
This is the relevant portion:
T[] larray = array;
if (larray == null) {
array = new T[newSize];
return;
}
if (larray.Length != newSize) {
T[] newArray = new T[newSize];
Array.Copy(larray, 0, newArray, 0, larray.Length > newSize? newSize : larray.Length);
array = newArray;
}
As you can see, it allocates a new array and then copies whatever it can from the existing array into the new array.
Arrays cannot be resized in C#.
Your first example assigns a new array to the variable arr, it doesn't resize the existing array.
Also Array.Resize is a misnomer: it actually creates a new array and copies the values.
The clue to that is with the ref keyword, which indicates that Array.Resize will be reassigning to arr.
Each of those examples actually creates a brand new array, copies the items one by one from the old to the new, and updates the reference.
If you have a collection where the size will change over time, you're almost always better off using a generic List<T>.

How do you insert a value into an array, preserving order?

I have a string array, and I want to add a new value somewhere in the center, but don't know how to do this. Can anyone please make this method for me?
void AddValueToArray(String ValueToAdd, String AddAfter, ref String[] theArray) {
// Make this Value the first value
if(String.IsNullOrEmpty(AddAfter)) {
theArray[0]=ValueToAdd; // WRONG: This replaces the first Val, want to Add a new String
return;
}
for(int i=0; i<theArray.Length; i++) {
if(theArray[i]==AddAfter) {
theArray[i++]=ValueToAdd; // WRONG: Again replaces, want to Add a new String
return;
}
}
}
You can't add items to an array, it always remains the same size.
To get an array with the item added, you would need to allocate a new array with one more item, and copy all items from the original array to the new array.
This is certainly doable, but not efficient. You should use a List<string> instead, which already has an Insert metod.
This would work only in some particular case.
public static void AddValueToArray(ref String[] theArray, String valueToAdd, String addAfter) {
var count=theArray.Length;
Array.Resize(ref theArray, 1+count);
var index=Array.IndexOf(theArray, addAfter);
var array=Array.CreateInstance(typeof(String), count-index);
Array.Copy(theArray, index, array, 0, array.Length);
++index;
Array.Copy(array, 0, theArray, index, array.Length);
theArray[index]=valueToAdd;
}
Here's a sample, but it works with Type, you might need to modify the type you need. It is an example of copying array recursively.
How to find the minimum covariant type for best fit between two types?
See how IList Insert method is implemented

How delete an item from struct array in C#

I have a struct in C# and I define and array list of my struct based on my code that I express here. I add items in my array list, but I need to delete a few rows from my list too. Could you help me how can I delete item or items from my struct array list:
public struct SwitchList
{
public int m_Value1, m_Value2;
public int mValue1
{
get { return m_Value1; }
set {m_Value1 = value; }
}
public int mValue2
{
get { return m_Value2; }
set {m_Value2 = value; }
}
}
//Define an array list of struct
SwitchList[] mSwitch = new SwitchList[10];
mSwitch[0].mValue1=1;
mSwitch[0].mValue2=2;
mSwitch[1].mValue1=3;
mSwitch[1].mValue2=4;
mSwitch[2].mValue1=5;
mSwitch[2].mValue2=6;
Now how can I delete one of my items, for example item 1.
Thank you.
Arrays are fixed length data structures.
You will need to create a new array, sized one less than the original and copy all items to it except the one you want to delete and start using the new array instead of the original.
Why not use a List<T> instead? It is a dynamic structure that lets you add and remove items.
You will need to move elements around and resize the array (which is expensive), since there is some complexity there you going to want to hide it in class that just presents the collection without exposing the implementation details of how its stored. Fortunately Microsoft has already provided a class that does just this called List<T> which along with a few other collection types in System.Collections.Generic namespace meet most common collection needs.
as a side note, you should use auto-properties instead of the trivial property style that you ha
That's not possible, because an array is a fixed size block of elements. Because structs are values types and not reference types, you also can't just set the element zo null. One option would be to create a new smaller array and to copy your remaining values to the new array. But the better approach would be to use a List in my opinion.
If you really, really want to use arrays and move things around, here are some examples of how to do it:
{
// Remove first element from mSwitch using a for loop.
var newSwitch = new SwitchList[mSwitch.Length - 1];
for (int i = 1; i < mSwitch.Length; i++)
newSwitch[i - 1] = mSwitch[i];
mSwitch = newSwitch;
}
{
// Remove first element from mSwitch using Array.Copy.
var newSwitch = new SwitchList[mSwitch.Length - 1];
Array.Copy(mSwitch, 1, newSwitch, 0, mSwitch.Length - 1);
mSwitch = newSwitch;
}

C#: Setting all values in an array with arbitrary dimensions

I'm looking for a way to set every value in a multidimensional array to a single value. The problem is that the number of dimensions is unknown at compile-time - it could be one-dimensional, it could be 4-dimensional. Since foreach doesn't let you set values, what is one way that I could achieve this goal? Thanks much.
While this problem appears simple on the surface, it's actually more complicated than it looks. However, by recognizing that visiting every position in a multidimensional (or even jagged) array is a Cartesian product operation on the set of indexes of the array - we can simplify the solution ... and ultimately write a more elegant solution.
We're going to leverage Eric Lippert's LINQ Cartesian Product implementation to do the heavy lifting. You can read more about how that works on his blog if you like.
While this implementation is specific to visiting the cells of a multidimensional array - it should be relatively easy to see how to extend it to visit a jagged array as well.
public static class EnumerableExt
{
// Eric Lippert's Cartesian Product operator...
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct =
new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
}
class MDFill
{
public static void Main()
{
// create an arbitrary multidimensional array
Array mdArray = new int[2,3,4,5];
// create a sequences of sequences representing all of the possible
// index positions of each dimension within the MD-array
var dimensionBounds =
Enumerable.Range(0, mdArray.Rank)
.Select(x => Enumerable.Range(mdArray.GetLowerBound(x),
mdArray.GetUpperBound(x) - mdArray.GetLowerBound(x)+1));
// use the cartesian product to visit every permutation of indexes
// in the MD array and set each position to a specific value...
int someValue = 100;
foreach( var indexSet in dimensionBounds.CartesianProduct() )
{
mdArray.SetValue( someValue, indexSet.ToArray() );
}
}
}
It's now trivial to factor this code out into a reusable method that can be used for either jagged or multidimensional arrays ... or any data structure that can be viewed as a rectangular array.
Array.Length will tell you the number of elements the array was declared to store, so an array of arrays (whether rectangular or jagged) can be traversed as follows:
for(var i=0; i<myMDArray.Length; i++)
for(var j=0; j < myMDArray[i].Length; i++)
DoSomethingTo(myMDArray[i][j]);
If the array is rectangular (all child arrays are the same length), you can get the Length of the first array and store in a variable; it will slightly improve performance.
When the number of dimensions is unknown, this can be made recursive:
public void SetValueOn(Array theArray, Object theValue)
{
if(theArray[0] is Array) //we haven't hit bottom yet
for(int a=0;a<theArray.Length;a++)
SetValueOn(theArray[a], theValue);
else if(theValue.GetType().IsAssignableFrom(theArray[0].GetType()))
for(int i=0;i<theArray.Length;i++)
theArray[i] = theValue;
else throw new ArgumentException(
"theValue is not assignable to elements of theArray");
}
I think there is no direct way of doing this, so you'll need to use the Rank property to get the number of dimensions and a SetValue method (that takes an array with index for every dimension as argument).
Some code snippet to get you started (for standard multi-dimensional arrays):
bool IncrementLastIndex(Array ar, int[] indices) {
// Return 'false' if indices[i] == ar.GetLength(i) for all 'i'
// otherwise, find the last index such that it can be incremented,
// increment it and set all larger indices to 0
for(int dim = indices.Length - 1; dim >= 0; dim--) {
if (indices[dim] < ar.GetLength(dim)) {
indices[dim]++;
for(int i = dim + 1; i < indices.Length; i++) indices[i] = 0;
return;
}
}
}
void ClearArray(Array ar, object val) {
var indices = new int[ar.Rank];
do {
// Set the value in the array to specified value
ar.SetValue(val, indices);
} while(IncrementLastIndex(ar, indices));
}
The Array.Clear method will let you clear (set to default value) all elements in a multi-dimensional array (i.e., int[,]). So if you just want to clear the array, you can write Array.Clear(myArray, 0, myArray.Length);
There doesn't appear to be any method that will set all of the elements of an array to an arbitrary value.
Note that if you used that for a jagged array (i.e. int[][]), you'd end up with an array of null references to arrays. That is, if you wrote:
int[][] myArray;
// do some stuff to initialize the array
// now clear the array
Array.Clear(myArray, 0, myArray.Length);
Then myArray[0] would be null.
Are you saying that you want to iterate through each element and (if available) each dimension of an array and set each value along the way?
If that's the case you'd make a recursive function that iterates the dimensions and sets values. Check the Array.Rank property on MSDN and the Array.GetUpperBound function on MSDN.
Lastly, I'm sure generic List<T> has some sort of way of doing this.

Deep Copy with Array

Why doesn't ICloneable's Clone method return a deep copy?
Here is some sample code:
class A : ICloneable
{
public int x = 2;
public A(int x)
{
this.x = x;
}
public A copy()
{
A a = new A(this.x);
return a;
}
public object Clone()
{
A a = new A(this.x);
return a;
}
}
In the Main method :
A[] Array1 = new A[4] ;
Array1[0] = new A(0);
Array1[1] = new A(1);
Array1[2] = new A(2);
Array1[3] = new A(3);
A[] Array2 = new A[10];
Array. Copy(Array1, Array2, 4);
Array2[2].x = 11;
for (int i = 0; i < 4; i++)
Console.WriteLine($"Index {i} value: {Array1[i].x}");
Remembering that I've only changed element index 2 in Array2, here is the output from the code above, listing the values in Array1:
Index 0 value: 0
Index 1 value: 1
Index 2 value: 11
Index 3 value: 3
Index 2 in Array1 has 11 even though I changed it in Array2 and class A implements ICloneable!
What then is the benefit of Array implementing ICloneable?
From http://msdn.microsoft.com/en-us/library/k4yx47a1.aspx:
"If sourceArray and destinationArray are both reference-type arrays or are both arrays of type Object, a shallow copy is performed. A shallow copy of an Array is a new Array containing references to the same elements as the original Array. The elements themselves or anything referenced by the elements are not copied"
There may be a better method than this, but one technique you could use is:
A[] array2 = array1.Select (a =>(A)a.Clone()).ToArray();
Array.Copy copies the values of the array, in this case, references. There is nothing in the documentation of Array.Copy() that indicates a check for classes that implement IClonable and call Clone() instead. You will need to loop through the array and call Clone() yourself.
BTW, yes, IClonable kind of sucks.
Array.Copy() does not use ICloneable. It simply copies values stored in each cell (which in this case are references to your A objects)
Ani's answer uses LINQ thus does not work for C# 2.0, however a same method can be done using the Array class's ConvertAll method:
A[] Array2 = Array.ConvertAll(Array1,a => (A)a.Clone());

Categories

Resources