change array size - c#

Is it possible to change an array size after declaration?
If not, is there any alternative to arrays?
I do not want to create an array with a size of 1000, but I do not know the size of the array when I'm creating it.

You can use Array.Resize(), documented in MSDN.
But yeah, I agree with Corey, if you need a dynamically sized data structure, we have Lists for that.
Important: Array.Resize() doesn't resize the array (the method name is misleading), it creates a new array and only replaces the reference you passed to the method.
An example:
var array1 = new byte[10];
var array2 = array1;
Array.Resize<byte>(ref array1, 20);
// Now:
// array1.Length is 20
// array2.Length is 10
// Two different arrays.

No, try using a strongly typed List instead.
For example:
Instead of using
int[] myArray = new int[2];
myArray[0] = 1;
myArray[1] = 2;
You could do this:
List<int> myList = new List<int>();
myList.Add(1);
myList.Add(2);
Lists use arrays to store the data so you get the speed benefit of arrays with the convenience of a LinkedList by being able to add and remove items without worrying about having to manually change its size.
This doesn't mean an array's size (in this instance, a List) isn't changed though - hence the emphasis on the word manually.
As soon as your array hits its predefined size, the JIT will allocate a new array on the heap that is twice the size and copy your existing array across.

You can use Array.Resize() in .net 3.5 and higher. 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.
(So you will need the memory available for both arrays as this probably uses Array.Copy under the covers)

Yes, it is possible to resize an array. For example:
int[] arr = new int[5];
// increase size to 10
Array.Resize(ref arr, 10);
// decrease size to 3
Array.Resize(ref arr, 3);
If you create an array with CreateInstance() method, the Resize() method is not working. For example:
// create an integer array with size of 5
var arr = Array.CreateInstance(typeof(int), 5);
// this not work
Array.Resize(ref arr, 10);
The array size is not dynamic, even we can resize it. If you want a dynamic array, I think we can use generic List instead.
var list = new List<int>();
// add any item to the list
list.Add(5);
list.Add(8);
list.Add(12);
// we can remove it easily as well
list.Remove(5);
foreach(var item in list)
{
Console.WriteLine(item);
}

In C#, arrays cannot be resized dynamically.
One approach is to use
System.Collections.ArrayList instead
of a native array.
Another (faster) solution is to
re-allocate the array with a
different size and to copy the
contents of the old array to the new
array.
The generic function resizeArray (below) can be used to do that.
public static System.Array ResizeArray (System.Array oldArray, int newSize)
{
int oldSize = oldArray.Length;
System.Type elementType = oldArray.GetType().GetElementType();
System.Array newArray = System.Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
System.Array.Copy (oldArray,newArray,preserveLength);
return newArray;
}
public static void Main ()
{
int[] a = {1,2,3};
a = (int[])ResizeArray(a,5);
a[3] = 4;
a[4] = 5;
for (int i=0; i<a.Length; i++)
System.Console.WriteLine (a[i]);
}

Used this approach for array of bytes:
Initially:
byte[] bytes = new byte[0];
Whenever required (Need to provide original length for extending):
Array.Resize<byte>(ref bytes, bytes.Length + requiredSize);
Reset:
Array.Resize<byte>(ref bytes, 0);
Typed List Method
Initially:
List<byte> bytes = new List<byte>();
Whenever required:
bytes.AddRange(new byte[length]);
Release/Clear:
bytes.Clear()

Use System.Collections.Generic.List

Use a List<T> instead. For instance, instead of an array of ints
private int[] _myIntegers = new int[1000];
use
private List<int> _myIntegers = new List<int>();
later
_myIntegers.Add(1);

In C#, Array.Resize is the simplest method to resize any array to new size, e.g.:
Array.Resize<LinkButton>(ref area, size);
Here, i want to resize the array size of LinkButton array:
<LinkButton> = specifies the array type
ref area = ref is a keyword and 'area' is the array name
size = new size array

private void HandleResizeArray()
{
int[] aa = new int[2];
aa[0] = 0;
aa[1] = 1;
aa = MyResizeArray(aa);
aa = MyResizeArray(aa);
}
private int[] MyResizeArray(int[] aa)
{
Array.Resize(ref aa, aa.GetUpperBound(0) + 2);
aa[aa.GetUpperBound(0)] = aa.GetUpperBound(0);
return aa;
}

If you really need to get it back into an array I find it easiest to convert the array to a list, expand the list then convert it back to an array.
string[] myArray = new string[1] {"Element One"};
// Convert it to a list
List<string> resizeList = myArray.ToList();
// Add some elements
resizeList.Add("Element Two");
// Back to an array
myArray = resizeList.ToArray();
// myArray has grown to two elements.

Use a List (where T is any type or Object) when you want to add/remove data, since resizing arrays is expensive. You can read more about Arrays considered somewhat harmful whereas a List can be added to New records can be appended to the end. It adjusts its size as needed.
A List can be initalized in following ways
Using collection initializer.
List<string> list1 = new List<string>()
{
"carrot",
"fox",
"explorer"
};
Using var keyword with collection initializer.
var list2 = new List<string>()
{
"carrot",
"fox",
"explorer"
};
Using new array as parameter.
string[] array = { "carrot", "fox", "explorer" };
List<string> list3 = new List<string>(array);
Using capacity in constructor and assign.
List<string> list4 = new List<string>(3);
list4.Add(null); // Add empty references. (Not Recommended)
list4.Add(null);
list4.Add(null);
list4[0] = "carrot"; // Assign those references.
list4[1] = "fox";
list4[2] = "explorer";
Using Add method for each element.
List<string> list5 = new List<string>();
list5.Add("carrot");
list5.Add("fox");
list5.Add("explorer");
Thus for an Object List you can allocate and assign the properties of objects inline with the List initialization. Object initializers and collection initializers share similar syntax.
class Test
{
public int A { get; set; }
public string B { get; set; }
}
Initialize list with collection initializer.
List<Test> list1 = new List<Test>()
{
new Test(){ A = 1, B = "Jessica"},
new Test(){ A = 2, B = "Mandy"}
};
Initialize list with new objects.
List<Test> list2 = new List<Test>();
list2.Add(new Test() { A = 3, B = "Sarah" });
list2.Add(new Test() { A = 4, B = "Melanie" });

This worked well for me to create a dynamic array from a class array.
var s = 0;
var songWriters = new SongWriterDetails[1];
foreach (var contributor in Contributors)
{
Array.Resize(ref songWriters, s++);
songWriters[s] = new SongWriterDetails();
songWriters[s].DisplayName = contributor.Name;
songWriters[s].PartyId = contributor.Id;
s++;
}

In case you cannot use Array.Reset (the variable is not local) then Concat & ToArray helps:
anObject.anArray.Concat(new string[] { newArrayItem }).ToArray();

Use a generic List (System.Collections.Generic.List).

Related

Add value to integer array in C#

How can I add a single Integer to an Integer Array?
if (valuesHigherThanAverage.Length == 0) valuesHigherThanAverage[valuesHigherThanAverage.Length] = arrayGetal;
else valuesHigherThanAverage[valuesHigherThanAverage.Length + 1] = arrayGetal;
I have this code and I have also tried with for or foreach loop but it doesn't worked. And I need to use an INT[] and may not use an List.
You can't add a new item in an array, you have to create a new array with size+1, copy all existing values, and then set the last item value.
An easier way is to use a List<int>, which will automatically resize if you run out of space. Calling the Add method suffices then.
Here a sample of an array resizing algorithm (Array.Resize could automate this, but this is just to show you how it should work):
int[] oldItems = new int[] { 1, 2, 3 };
int[] newItems = new int[oldItems.Length * 2];
for (int i = 0; i < oldItems.Length; i++)
{
newItems[i] = oldItems[i];
}
newItems[oldItems.Length + 1] = 4;
The array is not designed to be extended as new elements are added. You will need to call Array.Resize(Of T) to increase the size but this is will be quite inefficient.
Data types more in line for what you want to do is List<T>.
You cannot change the size of array like valuesHigherThanAverage.Length + 1. It has fixed size. You are crossing the upper bound of the array.
You can create a new Array with the length of the old array + 1.
public static int[] AddIntToArray(int[] sourceArray, int addValue)
{
int[] newArray = new int[sourceArray.Length + 1];
Array.Copy(sourceArray, newArray, sourceArray.Length);
newArray[newArray.Length] = addValue;
return newArray;
}

c# A better way to Copy/Merge multiple arrays into one array

Would anyone be able to advise if there's a better way to copy multiple arrays into a single array? The resulting array must have the elements in the same order such as arrayOne values first then arraySecond values next etc.
Following is a mockup of what I'm currently executing which working as expected. Looking for a smarter way of doing this.
// Initialise the first array.
string[] arrayOne = new string[5];
arrayOne[0] = "arrayOneValue[0]";
arrayOne[1] = "arrayOneValue[1]";
arrayOne[2] = "arrayOneValue[2]";
arrayOne[3] = "arrayOneValue[3]";
arrayOne[4] = "arrayOneValue[4]";
// Initialise the second array.
string[] arrayTwo = new string[6];
arrayTwo[0] = "arrayTwoValue[0]";
arrayTwo[1] = "arrayTwoValue[1]";
arrayTwo[2] = "arrayTwoValue[2]";
arrayTwo[3] = "arrayTwoValue[3]";
arrayTwo[4] = "arrayTwoValue[4]";
arrayTwo[5] = "arrayTwoValue[5]";
// Initialise the third array.
string[] arrayThree = new string[3];
arrayThree[0] = "arrayThreeValue[0]";
arrayThree[1] = "arrayThreeValue[1]";
arrayThree[2] = "arrayThreeValue[2]";
// string[] arrayN = new string[n]
//.
//.
//.
// Initialise the target array.
string[] finalArray = new string[arrayOne.Length + arrayTwo.Length + arrayThree.Length];
// ArrayN - string[] finalArray = new string[arrayOne.Length + arrayTwo.Length + arrayThree.Length + arrayN.Length];
// Copy/merge the three arrays into the target array.
Array.Copy(arrayOne, 0, finalArray, 0, arrayOne.Length);
Array.Copy(arrayTwo, 0, finalArray, arrayOne.Length, arrayTwo.Length);
Array.Copy(arrayThree, 0, finalArray, (arrayOne.Length + arrayTwo.Length), arrayThree.Length);
//.
//.
//.
//.
// ArrayN - Array.Copy(arrayN, 0, finalArray, (arrayOne.Length + arrayTwo.Length + arrayN), arrayN.Length) ?;
As you can see for arrayN the code can get longer. I have a maximum of 5 arrays I'm trying to copy into one array, therefore, it's manageable. I'm using this technique as part of a WebAPI where a collection of oracle parameter objects are consolidated based on business rules to be passed to several Oracle stored procedures. Any advise here is appreciated. Thanks in advance.
Result
Console output
/*--- Destination array -
arrayOneValue[0]
arrayOneValue[1]
arrayOneValue[2]
arrayOneValue[3]
arrayOneValue[4]
arrayTwoValue[0]
arrayTwoValue[1]
arrayTwoValue[2]
arrayTwoValue[3]
arrayTwoValue[4]
arrayTwoValue[5]
arrayThreeValue[0]
arrayThreeValue[1]
arrayThreeValue[2]*/
You can just use LINQ .Concat so that you don't need manually take care of arrays lengths and offsets:
var finalArray = arrayOne.Concat(arrayTwo).Concat(arrayThree).ToArray();
It may be little less performant than using Array.Copy, but this code is much more readable, maintainable and error-safe, which is more important.
By creating a big array up front, then using Array.Copy, we can achieve very reasonable speeds for concatenating, even with a very large number of arrays:
public static T[] ConcatArrays<T>(params T[][] p)
{
var position = 0;
var outputArray = new T[p.Sum(a => a.Length)];
foreach (var curr in p)
{
Array.Copy(curr, 0, outputArray, position, curr.Length);
position += curr.Length;
}
return outputArray;
}
So, now we can either:
string bigArray = ConcatArrays(arrayOne, arrayTwo, arrayThree)
or
string[][] arrays = new[]{arrayOne, arrayTwo, arrayThree};
string bigArray = ConcatArrays(arrays);
var one = new [] { arrayOne, arrayTwo, arrayThree }.SelectMany(x => x);
You can put your input arrays in a collection and iterate over them. I only mention this because this may be more efficient than using LINQ. It depends on the data you're dealing with, but probably not enough to make a difference.
In the code below, on my machine, LINQ takes 9000-13000 ticks (one tick = 100 ns) while calling Array.Copy is ~500 ticks.
public static void Benchmark1()
{
var arr1 = Enumerable.Range(1,10000).ToArray();
var arr2 = Enumerable.Range(10001,20000).ToArray();
var arr3 = Enumerable.Range(20001,30000).ToArray();
var arr4 = Enumerable.Range(30001,40000).ToArray();
var sw = Stopwatch.StartNew();
var result = arr1.Concat(arr2).Concat(arr3).Concat(arr4).ToArray();
sw.Stop();
Console.WriteLine($"Elpased ticks: {sw.ElapsedTicks}");
}
public static void Benchmark2()
{
var arr1 = Enumerable.Range(1,10000).ToArray();
var arr2 = Enumerable.Range(10001,20000).ToArray();
var arr3 = Enumerable.Range(20001,30000).ToArray();
var arr4 = Enumerable.Range(30001,40000).ToArray();
var arrays = new List<int[]>() {arr1, arr2, arr3, arr4};
var sw = Stopwatch.StartNew();
int finalLen = 0;
foreach (var arr in arrays)
{
finalLen += arr.Length;
}
var result = new int[finalLen];
int currentPosition = 0;
foreach (var arr in arrays)
{
Array.Copy(arr, 0, result, currentPosition, arr.Length);
currentPosition += arr.Length;
}
sw.Stop();
Console.WriteLine($"Elpased ticks: {sw.ElapsedTicks}");
}
Do you have to use arrays? Use lists and AddRange(). If you need to have an array eventually then just call ToArray() in the end.

Is there a way to expand a one-dimensional Array into a 2D Array with the original values in the [0] index of the 2D Array in C#?

I have an Array with Category Names, but now i Need to assign a few Counters to each Category.
Is there a way to expand my 1D-Array to a 2D-Array in C#?
Thanks for helping!
Edit:
PerformanceCounterCategory[] categories;
categories = PerformanceCounterCategory.GetCategories();
string[] categoryNames = new string[categories.Length];
string[] categoryNames_en = new string[categories.Length];
for (int objX = 0; objX < categories.Length; objX++)
{
categoryNames[objX] = categories[objX].CategoryName;
}
Array.Sort(categoryNames);
for (int objX = 0; objX < categories.Length; objX++)
{
Console.WriteLine("{0,4} - {1}", objX + 1, categoryNames[objX]);
}
I have the Array categoryNames with all the Names of the Categories, but in every Category there are a few Counters which i want to assign to their Category somehow...
Unfortunately you can't use Array.Copy since the source and destination array do not have the same dimensions.
Furthermore, you can't expand arrays in C#, since they are initialized with a fixed size.
What you can do is create a new array with a second dimonesion and copy the values over and set the second dimension to a default value.
void Main()
{
int[] sourceCollection = new [] {1,2,3,4,5,6,7} ;
var result = CopyArrayValues(sourceCollection, 2);
result.Dump();
}
//create a new 2d array
T[,] CopyArrayValues<T>(T[] DataSource, int SecondLength)
{
//Initialize the new array
var Target = new T[DataSource.Length, SecondLength];
//Copy values over
for (int i = 0; i < DataSource.Length; i++)
{
Target[i, 0] = DataSource[i];
}
return Target;
}
Output:
If it's ok for you to have array of arrays, you can do something along this pattern:
int[] sourceCollection = new[] { 1, 2, 3, 4, 5, 6, 7 };
int[][] arr = sourceCollection.Select(i => Enumerable.Range(i, 4).ToArray()).ToArray();

How to save array in list by value not reference in C#

I want to save my current state of array and later change that array but when I save my array in list and then change my array, array in list also changes. This is a sample code and a part of my code :
void main()
{
List<int[]> lisarr = new List<int[]>();
int[] a = new int[1];
a[0] = 1;
lisarr.Add(a);
a[0] = 10;
// at this time lisarr[0] also changes
....
}
If you trace this code notice that my array in list also change, but I don't want this. How can I fix this problem?
Add a copy of your array:
List<int[]> lisarr = new List<int[]>();
int[] a = new int[1];
a[0] = 1;
lisarr.Add(a.ToArray());
a[0] = 10;

How to initialize an array of arrays (or jagged array) using CodeDom?

I'm trying to use CodeDom to generate C# (.Net 2.0) code that would do the following:
int[][] myArray = new int[someSize][];
In CodeDom, initializing an array requires a CodeArrayCreateExpression. The MSDN says:
If a language allows arrays of arrays, it is possible to create them by nesting a CodeArrayCreateExpression within a CodeArrayCreateExpression.
The way I understand it, the only possibility is to write something like this:
// Declaration and initialization of myArray
CodeVariableDeclarationStatement variable =
new CodeVariableDeclarationStatement("System.Int32[][]", "myArray",
new CodeArrayCreateExpression("System.Int32[][]",
new CodeExpression[] { new CodeArrayCreateExpression("System.Int32[]", 0) }));
But this generates this:
int[][] myArray = new int[][] { new int[0] };
That's not perfect but I could do with it if I knew the size of myArray at generation time, which I don't.
I could write a function that does the initialization and call it in CodeDom but it would be nicer if I could do it in pure CodeDom. Did I miss something ?
[EDIT] Background information
The idea is to automatically generate an adapter between two object representations. I have a meta-description (some kind of IDL) saying: "I have a container object which has a field of type int[][]" and two representations of this container:
// Internal representation
public class InternalContainer {
int[][] myArray;
}
// Network representation
public class NetworkContainer {
int[][] myArray;
}
Thus the question of generating code that can adapt to any size of array.
You have the following workaround to create a jagged array with a dynamic length:
Create the dom equivalent of
ELEMENTTYPE[] array = (ELEMENTTYPE[])Array.CreateInstance(typeof(ELEMENTTYPE), length);
ELEMENTTYPE can be any type, be it an array or not.
Here's my solution, using a CodeSnippetExpression
public static DOM.CodeExpression NewArray (this Type type, int dim, int size) {
string dims = String.Concat(Enumerable.Repeat("[]", dim - 1).ToArray());
return new DOM.CodeSnippetExpression(string.Format("new {0}[{1}]{2}", type.FullName, size, dims));
}
CodeArrayCreateExpression CodeArrayCreateExpression(Array array)
{
CodeArrayCreateExpression arrayCreateExpression = new CodeArrayCreateExpression(array.GetType(), array.GetLength(0));
if (array.GetType().GetElementType().IsArray)
{
CodeArrayCreateExpression[] values = new CodeArrayCreateExpression[array.GetLength(0)];
for (int j = 0; j < array.GetLength(0); j++)
{
values[j] = this.CodeArrayCreateExpression((Array)array.GetValue(j));
}
arrayCreateExpression.Initializers.AddRange(values);
}
else if(array.GetType().GetElementType().IsPrimitive)
{
CodeCastExpression[] values = new CodeCastExpression[array.GetLength(0)];
for (int j = 0; j < values.Length; j++)
{
values[j] = new CodeCastExpression();
values[j].Expression = new CodePrimitiveExpression(array.GetValue(j));
values[j].TargetType = new CodeTypeReference(array.GetType().GetElementType());
}
arrayCreateExpression.Initializers.AddRange(values);
}
return arrayCreateExpression;
}

Categories

Resources