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);
}
Related
I have a dll which gives me as an output an Object[,]
{Name = "Object[,]" FullName = "System.Object[,]"}
I am trying to convert it to Object[] to be able to read it properly, as it is a two columns object.
I have tried to cast it Object[] values = (Object[])data;, but I obtained the error from the tittle:
Unable to cast object of type 'System.Object[,]' to type 'System.Object[]'.
Is there any easy way to perform this operation? I would like to make a dictionary out of it.
Thanks in advance
Rather than using it as an Object[] (which it isn't), use the System.Array API:
var dictionary = new Dictionary<string, string>(); // For example
Array array = (Array) data;
for (int i = 0; i < array.GetLength(0); i++)
{
string key = (string) array.GetValue(i, 0);
string value = (string) array.GetValue(i, 1);
dictionary[key] = value;
}
You can only cast an instance of any type to another one if it implements both types. However object[,] does not derive from object[] so you can´t cast it to that type. At least you should provide which dimension (/column) of the array you want to handle further.
However it is unlcear why you need this. If you´re only interested on the colums instead of the rows then you might simply call myArr[i, 0] or whatever column you´re interested in within a loop on the first dimension of the array.
If you want to iterate your multidimensional array you may either flatten it:
foreach(var on in myArray)
Console.WriteLine(o);
Which will simply loop all the elements without considering its position in the array or
for(int i = 0; i < myArray.GetLength(myColumnIndex); i++)
Console.WriteLine(myArray[i, myColumnIndex]);
Whereby you get only those elements within the given column.
Well of course you cannot cast a multidimensional array to an single dimension array. It is illegal. Check Casting
But as a solution to your problem could be the following logic
object[,] multiDimensionalArray = new object[,]
{
{1,2}, //first pair
{3,4}, //second pair
{5,6} //third pair
};
Dictionary<object, object> dict = new Dictionary<object, object>();
//total number of elements //number of dimensions
int pairs = multiDimensionalArray.Length / multiDimensionalArray.Rank;
//or you can use i < multiDimensionalArray.GetLength(0);
for(int i = 0; i < pairs; i++)
{
dict.Add(multiDimensionalArray[i, 0], multiDimensionalArray[i, 1]);
}
here is the code adding data to the list, after which i return the list. Problem is that the last set of data seems to be overwriting everything else in the list
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Your code isn't adding any new objects to the list, it modifies and adds the same object. In the end, the list contains X references to the same object instance.
In general it is consider bad practice to declare a variable outside the scope in which it is used. You could have avoided this problem by writing:
var myArray=jsonObject["mydetails"].GetArray();
for (int k=0; k < myArray.Count; k++)
{
var myJsonObject=myArray[k].GetObject();
var obj=new MyAccountObject();
obj.accountNumber = myJsonObject["id"].GetString();
...
}
Notice that instead of calling GetArray() and GetObject() in each line (essentially doing the job of extracting the array multiple times) I stored them in separate variables. This will result in far less CPU and memory usage.
You always add the same object obj to the list. You need to create a new in the top of the loop.
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
obj = new ObjectType(); // you know better the type of the object you want to create.
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Without the the line obj = new ... you change the properties accountNumber, accountName and accountBall of the same object instance. At the end you add always that object reference to the list. So it seems that the last run of the loop changes all objects.
This question already has answers here:
Remove element of a regular array
(15 answers)
Closed 9 years ago.
string[] columns
I want to delete the item on an index specified by a variable of type int.
How do I do this ?
I tried
columns.RemoveAt(MY_INT_HERE);
But apparently this does not works.
Array is immutable class, you can't change it, all you can do is to re-create it:
List<String> list = columns.ToList(); // <- to List which is mutable
list.RemoveAt(MY_INT_HERE); // <- remove
string[] columns = list.ToArray(); // <- back to array
May be the best solution is to redesign your code: change immutable array into List<String>:
List<String> columns = ...
columns.RemoveAt(MY_INT_HERE);
If you don't want to use linq you can use this function :
public string[] RemoveAt(string[] stringArray, int index)
{
if (index < 0 || index >= stringArray.Length)
return stringArray;
var newArray = new string[stringArray.Length - 1];
int j = 0;
for (int i = 0; i < stringArray.Length; i++)
{
if(i == index)continue;
newArray[j] = stringArray[i];
j++;
}
return newArray;
}
You use it like that : columns = RemoveAt(columns, MY_INT_HERE)
You can also make it to an extension method.
You cannot delete items in an array, because the length of a C# array is fixed at the time when it is created, and cannot be changed after that.
You can null out the corresponding element to get rid of the string, or use LINQ to produce a new array, like this:
columns = columns.Take(MY_INT_HERE-1).Concat(columns.Skip(MY_INT_HERE)).ToArray();
You need to add using System.Linq at the top of your C# file in order for this to compile.
However, using a List<string> would be a better solution:
List<string> columns;
columns.RemoveAt(MY_INT_HERE);
Try one of the following (depending on what you need):
columns[MY_INT_HERE] = null;
columns[MY_INT_HERE] = string.Empty;
...otherwise you'll just have to create a new array which has a length of 1 less than your current array, and copy the values over.
If you want something more flexible, you might use a something like a List<string>, where you can use RemoveAt()
Arrays are faster for the computer to work with but slower for a programmer. You will have to find that value with a loop or some other means, then set that position to null. You will end up with an empty space in the array. You could reallocate the array etc etc...
What is easier to use for relatively small amounts of data is a List. You can do myList.RemoveAt(100); and it will work nicely.
You can not delete it.You can recreate the array or I advice you to use List<string> for the same.
List<string> columns = new List<string>();
columns.RemoveAt(1);
It will remove the 2nd element from your List<String> columns
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
how to inset a new array to my jagged array
i have a problem, where i dont know how i can make a string array variable in array length.
i have this code now below:
string[] p = new string[10];
int num = 0;
foreach (Product products in GetAllProducts())
{
//do something
p[num]= "some variable result"
num++
}
The problem is, that i dont know how many of "p" i will get, although i know it atleast will be less than 10.
but if i put it on 0, i will get an error when i start it, because it doesn't know the "p[num]"
So i am looking for some way to make "p" have a variable length.
anyone could help me out a bit? thanx
============Solved==========
List<string> p = new List<string>();
int num = 0;
foreach (Product products in GetAllProducts())
{
string s= null;
//do something ( create s out of multiple parts += s etc.)
p.add(s)
num++
}
thanx to solution poster
Use an List<string> instead of an array, if you do not know the number of items you will need to add.
Your array length cannot be modified after it has been instantiated. Use ArrayList or Generic Lists.
var p = new new List<string>(10);
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
What does GetAllProducts() return? Does it have a count or a length?! You should call that first, save it in a variable, get the count/length and then declare your array!
There's two solution.
If you want to keep using array :
int num = 0;
var list = GetAllProducts();
string[] p = new string[list.Length]; // Or list.Count if this is a collection
foreach (Product products in list)
{
//do something
p[num] = "some variable result";
num++;
}
Otherwise you should use a List like this :
List<string> p = new List<string>();
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
Use Array.Resize() method, which allows to resize it (by n number of indexes).
In my exmaple I will reize by 1 on each step of the way:
string[] array = new string[3]; //create array
for (int i = 0; i < 5; i++)
{
if (array.Length-1 < i) //checking for the available length
{
Array.Resize(ref array, array.Length + 1); //when to small, create a new index
}
array[i] = i.ToString(); //add an item to array[index] - of i
}
Because your code is using a foreach on the result from GetAllProducts, then GetAllProducts must be returning a IEnumerable collection. Probably the best solution would be to simply assign the result of GetAllProducts to such a collection. For example, perhaps it already returns a list of strings? So you can do:
List<string> strings = GetAllProducts();
There is no need to have a foreach loop to create an array when you already have a collection anyway being returned from GetAllProducts.
Or simply:
var strings = GetAllProducts();
to let the compiler work out the type of strings.
Most things you can do with an array you can also do with a List, and some more (such as adding items to the end of the List).
Perhaps you can post the signature of GetAllProducts (especially its return type) so we can better advise you?
I see many gave you the right answer which is the use of Lists. If you still need an array in the end, you can easily convert your list into an Array like this :
string[] tempArray = myList.ToArray();
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());