Deep Copy with Array - c#

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());

Related

Issue with dynamically creating jagged array in C#

I am trying to store each iteration of an array as it is being sorted through. For some reason the jagged array I return just becomes an array of the final sorted array. My code is below I cannot figure out why any help would be really appreciated. Thanks.
namespace SortingUI.Utils
{
public class Sorting
{
public static int[][] SortInt(int[] originalArray)
{
int length = originalArray.Length;
int tempVal, smallest;
int[][] iterations = new int[length-1][];
for (int i = 0; i < length - 1; i++)
{
smallest = i;
for (int j = i + 1; j < length; j++)
{
if (originalArray[j] < originalArray[smallest])
{
smallest = j;
}
}
tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
iterations[i] = originalArray;
}
return iterations;
}
}
}
If i understand your problem, the reason you are getting the same values (and not a snapshot) is because you are storing a reference to the array, and not a copy of the values themselves.
Arrays are reference types, so when you assign them to another variable you are only copying reference and not the contents. If you change the contents, all the references will reflect that
You can make use of Array.Copy to copy the values at the point in time from the originalArray
...
var tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
// Create some new memory
iterations[i] = new int[originalArray.Length];
// Copy the contents
Array.Copy(originalArray, iterations[i], originalArray.Length);
Note this is totally untested and i have no idea if the rest of your code is working as intended
Additional Resources
Array.Copy Method
Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.
Arrays (C# Programming Guide)
Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable,
you can use foreach iteration on all arrays in C#.

Using Linq Except with two lists of int arrays

Is it possible to use except with two lists of int arrays, like so:
List<int[]> a = new List<int[]>(){ new int[]{3,4,5}, new int[]{7,8,9}, new int[]{10,11,12} };
List<int[]> b = new List<int[]>(){ new int[]{6,7,9}, new int[]{3,4,5}, new int[]{10,41,12} };
var c = a.Except(b);
and exepecting {3,4,5} to be absent of the enumerable c? Of course I tried and this one is not working. Is there a solution as efficient as Except? Or even better, faster?
In .NET, arrays are only equal to another if they are the exact same array object. So two distinct arrays which have the same contents are not considered equal:
int[] x = new int[] { 1, 2 };
int[] y = new int[] { 1, 2 };
Console.WriteLine(x == y); // false
In order to check the equality based on the contents, you can use Enumerable.SequenceEqual:
Console.WriteLine(x.SequenceEqual(y)); // true
Of course that doesn’t help you directly when trying to use Enumerable.Except, since by default that will use the default equality comparer which only checks for equality (and since every array is inequal to every other array except itself…).
So the solution would be to use the other overload, and provide a custom IEqualityComparer which compares the arrays based on their content.
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] a, int[] b)
{
return a.SequenceEqual(b);
}
public int GetHashCode(int[] a)
{
return a.Sum();
}
}
Unfortunately, just delegating to SequenceEqual is not enough. We also have to provide a GetHashCode implementation for this to work. As a simple solution, we can use the sum of the numbers in the array here. Usually, we would want to provide a strong hash function, which tells a lot about the contents, but since we are only using this hash function for the Except call, we can use something simple here. (In general, we would also want to avoid creating a hash value from a mutable object)
And when using that equality comparer, we correctly filter out the duplicate arrays:
var c = a.Except(b, new IntArrayEqualityComparer());
That's because default EqualityComparer for int array returns false for to arrays with same values:
int[] a1 = { 1, 2, 3 };
int[] a2 = { 1, 2, 3 };
var ec = EqualityComparer<int[]>.Default;
Console.WriteLine(ec.Equals(a1, a2));//result is false
You can fix it by implementing your own EqualityComparer and passing its instance to Except method (see documentation).
You can also read about arrays comparison in C# here.

How to dynamically resize an array?

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;
}
}
}

Issue with editing list<double[]> in c#

I am passing a list of type double[] to a function in a class, editing the values within a function using a tempList, then returning the edited values.
But the originalList being passed is being edited as well which I do not want them edited to match the tempList.
Here is the code.
List<double[]> newList = new List<double[]();
newList = myClass.myFunction(value, originalList);
// myClass
...
// myFunction
public List<double[]> myFunction(int value, List<double[]> myList)
{
List<double[]> tempList = new List<double[]>();
for (int i = 0; i < myList).Count; i++)
{
tempList.Add(myList[i]);
}
// Do stuff to edit tempList
return tempList;
}
Bear in mind that arrays are reference types. When you add an array to tempList, only a reference to the array is being added, so that myList and tempList both refer to the same double[] objects.
Instead, you need to make a clone of the arrays:
for (int i = 0; i < myList.Count; i++)
{
tempList.Add((double[])myList[i].Clone());
}
An array, here double[], is a reference type, so the line
tempList.Add(myList[i]);
is adding a reference to the original array. Then when you edit tempList you're editing the original array. Make a copy like this:
tempList.Add(myList[i].ToArray());
You are adding the reference to the array to the new list, but not making a copy of the contents of each array. Your copy should look something like this:
foreach (double[] item in myList)
{
double[] copy = new double[item.Length];
Array.Copy(item, copy);
templist.Add(copy);
}
The problem you are having is double[] is a reference type, not a value type, so when you are adding it to your tempList, you are adding a reference to the original object, not a new object. You actually need to create a new double[] before adding it to tempList so you are not working on the original object.
Assuming you can use LINQ, you do not need to loop. You can do something like:
var tempList = myList.Select(x => x.ToArray()).ToList();
This is because Collections/reference types are passed by reference. (Actually the holding variable is passed by value, but the all variables point to same reference).
For detail explanation, read this SO Answer
If you want that modifications in my Function does not reflect in original collection, you have to copy/clone it and then pass to myFunction.
Example
newList = myClass.myFunction(value, (List<double>)originalList.Clone());
tempList.Add(myList[i]);
means that you add the reference to the double[] object on index i to temp list.
therefore, if you edit the value of that object, you will get the chances on both of the lists.
if you want to have a different cloned lists that won't affect each other you will have to do that:
List<double[]> tempList = new List<double[]>();
for (int i = 0; i < myList).Count; i++)
{
double[] originalListItem = myList[i];
// the most important step here!!! - clone the originalListItem to clonedListItem
tempList.Add(clonedListItem);
}
// Do stuff to edit tempList
return tempList;
You are copying the double[] reference to the new list, this is a shallow copy.
You need a deep copy and create new double arrays to edit the temp arrays without changing the original arrays.
You are inserting references to the array in the tempList, not a copy of the array. So if you change a value in the tempList, you are changing the original array.
This code will work better:
for (int i = 0; i < myList.Count; i++)
{
var copy = new Double[myList[i].Length];
Array.Copy(myList[i], copy, myList[i].Length);
tempList.Add(copy);
}

Dynamic array in C#

Is there any method for creating a dynamic array in C#?
Take a look at Generic Lists.
Expanding on Chris and Migol`s answer with a code sample.
Using an array
Student[] array = new Student[2];
array[0] = new Student("bob");
array[1] = new Student("joe");
Using a generic list. Under the hood the List<T> class uses an array for storage but does so in a fashion that allows it to grow effeciently.
List<Student> list = new List<Student>();
list.Add(new Student("bob"));
list.Add(new Student("joe"));
Student joe = list[1];
Sometimes plain arrays are preferred to Generic Lists, since they are more convenient (Better performance for costly computation -Numerical Algebra Applications for example, or for exchanging Data with Statistics software like R or Matlab)
In this case you may use the ToArray() method after initiating your List dynamically
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
list.Add("three");
string[] array = list.ToArray();
Of course, this has sense only if the size of the array is never known nor fixed ex-ante.
if you already know the size of your array at some point of the program it is better to initiate it as a fixed length array. (If you retrieve data from a ResultSet for example, you could count its size and initiate an array of that size, dynamically)
List<T> for strongly typed one, or ArrayList if you have .NET 1.1 or love to cast variables.
You can do this with dynamic objects:
var dynamicKeyValueArray = new[] { new {Key = "K1", Value = 10}, new {Key = "K2", Value = 5} };
foreach(var keyvalue in dynamicKeyValueArray)
{
Console.Log(keyvalue.Key);
Console.Log(keyvalue.Value);
}
Use the array list which is actually implement array. It takes initially array of size 4 and when it gets full, a new array is created with its double size and the data of first array get copied into second array, now the new item is inserted into new array.
Also the name of second array creates an alias of first so that it can be accessed by the same name as previous and the first array gets disposed
Dynamic Array Example:
Console.WriteLine("Define Array Size? ");
int number = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter numbers:\n");
int[] arr = new int[number];
for (int i = 0; i < number; i++)
{
arr[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < arr.Length; i++ )
{
Console.WriteLine("Array Index: "+i + " AND Array Item: " + arr[i].ToString());
}
Console.ReadKey();
you can use arraylist object from collections class
using System.Collections;
static void Main()
{
ArrayList arr = new ArrayList();
}
when you want to add elements you can use
arr.Add();
This answer seems to be the answer you are looking for Why can't I do this: dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" }
Read about the ExpandoObject here https://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject(v=vs.110).aspx
And the dynamic type here https://msdn.microsoft.com/en-GB/library/dd264736.aspx

Categories

Resources