I have a list List<MyClass>[,] myarraylist; and it is filled.
I want to copy it to List<MyClass>[,] mycopy then change mycopy without changing myarraylist.
What is the quickest way of doing this?
It kind of depends on what you really want to do. You can easily clone the array:
List<MyClass> mcopy = new List<MyClass>[marraylist.GetUpperBound(0)+1,marraylist.GetUpperBound(1)+1];
for (int i = 0; i < marraylist.GetUpperBound(0); ++i)
{
for (int j = 0; j < marraylist.GetUpperBound(1); ++j)
{
mcopy[i,j] = marraylist[i,j];
}
}
Now, that gives you a copy of the array. But, mcopy[1,2] has a reference to the same list as does marraylist[1,2]. If you modify that list, that is if you were to write:
mcopy[1,2].Add(new MyClass(...));
Then that would also modify the list that is referenced in marraylist[1,2].
If you want to create copies of the lists, then the code in your inner loop has to be:
mcopy[i,j] = new List<MyClass>(marraylist[i,j]);
That creates a new list, so if you modify the list at mcopy[1,2], you don't modify the list in the original array.
But that might not be what you want, either. Because although mcopy[1,2] contains a different list than marraylist[1,2], the lists have the same contents. So if you wrote mcopy[1,2][1].SomeProperty = 42;, then you'll also modify the contents of the object at marraylist[1,2][1], because they're the same object.
If you want to copies of the lists and copies of the objects, then your inner loop code becomes:
mcopy[i,j] = marraylist[i,j].Select(m => new MyClass(/* create from m */)).ToList();
The /* create from m */ comment means that you either pass m to the copy constructor (if you have one), or pass the individual parameters, or if you have a clone method on the class you'll use that. Somehow you want to make a deep copy of the MyClass instance.
Yes, it's complicated. The word "copy" is quite overloaded here, and how you proceed depends entirely on what definition of "copy" you're using. Do you want to make a copy of the array (just copy the references), the array's contents (create new lists with the same objects), or the lists' contents (create new lists with new objects that contain the same data)?
If MyClass has a copy constructor:
var newList = new List<MyClass>[oldList.GetLength(0), oldList.GetLength(1)];
for (int i = 0; i < oldList.GetLength(0); i++)
for (int j = 0; j < oldList.GetLength(1); j++)
newList[i, j] = oldList[i, j].Select(x => new MyClass(x)).ToList();
If it doesn't have a copy constructor, and you can't add one, you will have to write your own function to make a copy of MyClass.
newList[i, j] = oldList[i, j].Select(x => CloneMyClass(x)).ToList();
This may work. It is an extension method to 2D IEnumerables. That means it can be used with anything that implements the IEnumerable interface, as long as your class T implements ICloneable.
public static IEnumerable<IEnumerable<T>> Clone<T>(this IEnumerable<IEnumerable<T>> twoDList) where T : ICloneable
{
if (twoDList != null)
{
List<List<T>> result = new List<List<T>>();
for (int i = 0; i < twoDList.Count(); i++)
{
List<T> aList = new List<T>();
for (int j = 0; j < twoDList.ElementAt(i).Count(); j++)
{
aList.Add(twoDList.ElementAt(i).ElementAt(j));
}
result.Add(aList);
}
return result;
}
else
{
return null;
}
}
It should also work with jagged 2D structures that implement IEnumerable.
Example Usage follows:
List<List<MyClass>> cloned = original2DStructure.Clone();
Help on making your class implement ICloneable could be found here.
Related
I got 2 ArrayList objects on my project defined as
ArrayList final_list = new ArrayList();
ArrayList temp_list = new ArrayList();
I needed to fill my final_list with the other one, so I used a loop using final_list.Add(temp_list) inside of it, which works fine.
Here is an exemple about what my final_listobject looks like after the loop :
The fact is I need to process the datas after the loop. So I guess I'll have to do something like
for (int i = 0; i < final_list.Count; i++)
{
for (int j = 0; j < 6 ; j++)
{
// Retrieving my [0,0] , [0,1], ... , [final_list.Count,5] datas
}
}
but this isn't working.
Anyway, I'm even struggling on the correct syntax to use so I already tried hard coded things like final_list[0,1] or final_list[0][1]to display the 10 value for exemple, but it doesn't work.
How can I manage to do that ?
Seems you have a collection (final_list), which contains some collections inside. And now you want to process the inner most elements.
First of all, you'd better use generic collections instead of old ArrayList.
Generally, handling such a scenario can be done like this:
foreach( List<string> innerList in final_list)
{
foreach( var innerMostItem in innerList)
{
// process the element!
}
}
or equivelantely:
foreach( var innerList in final_list)
{
foreach( var innerMostItem in innerList as List<string>)
{
// process the element!
}
}
By the way, naming convention of C#, is to use camelCase for variables.
update
code snippet above is updated. Not the type casting in the inner loop!
Though innerList was originally an IEnumerable, it is retrieved from the final_list as an instance of object class. You need to explicitly cast it to ArrayList or you will get an exception.
I have an arraylist. it keeps arraylists in it. For example;
ar1 -> {2,3,46,67} keeps 4 members.
ar2 -> {28,96,67} keeps 3 members.
ar2 -> {56,32,67,54,214} keeps 5 members.
Ar_main[0]= ar1
Ar_main[1]= ar2
Ar_main[2]= ar3
i want to sort ar_main order by count of members. i used bubble sort algorithm. but it didn't work, can't we sort arraylist like this method?
private void sortArrayToAscending(ArrayList ar)
{
ArrayList ar1,ar2;
for (int i = 0; i < ar.Count - 1; i++)
for (int j = 1; j < ar.Count - i; j++)
{
ar1 = (ArrayList)ar[j];
ar2 = (ArrayList)ar[j-1];
if (ar1.Count < ar2.Count)
{
ArrayList temp = ar2;
ar2=ar1;
ar1=temp;
}
}
}
There is a built-in Sort method in the ArrayList that does the sorting for you. What you have to provide is an IComparer implementation that compares the list, making their length the criteria:
public void ArrayListSort()
{
var list = new ArrayList();
list.Sort(new LengthComparer());
}
class LengthComparer : IComparer
{
public int Compare(object x, object y)
{
var a = x as ArrayList;
var b = y as ArrayList;
// check for null if you need to!
return a.Count.CompareTo(b.Count);
}
}
However, unless you're actually using .NET 1.1, I'd recommend that you use List<T> instead of ArrayList, and the LINQ OrderBy method. This is type-safe, and I'd consider it more idiomatic C# nowadays. On top of that, it's way shorter:
var typedList = new List<List<int>>();
var sortedList = typedList.OrderBy(i => i.Count).ToList();
Be aware that the former is an in-place sort (altering the original list), whereas the latter copies the result into a new list.
I'm not allowed to comment yet or else I would. C# contains a built in static method in the ArrayList class. It sorts using the QuickSort algorithm. You may want to give it a try and see if it helps.Microsoft API Documentation ArrayList.Sort()
I try to write a program where Dictionary is indexed by List. (trust me i do, and yes there are option, but i like indexing by list). There is a minimal working (actually not working, only one last line which is a problem) example:
using System;
using System.Collections.Generic;
namespace test
{
class Program
{
static void Main(string[] args)
{
Dictionary<List<String>, int> h = new Dictionary<List<string>,int>();
List<String> w = new List<string> {"a"};
h.Add(w, 1);
w = new List<string>{"b"};
h.Add(w,2);
w = new List<string>{"a"};
int value = 0;
h.TryGetValue(w, out value);
Console.WriteLine(value+" "+h[w]);
}
}
if one debugs this program, he will clearly see that there two elements in h, but still these elements are not accessible via correct indexes --- h[w]. Am I wrong or is there something weird going on?
The problem with your app extends from the fact that:
new List<String> { "a" } != new List<String> { "a" }
Equality for lists checks to see if the two references refer to the same instance. In this case, they don't. You've instead created two Lists with the same elements...which doesn't make them equal.
You can fix the problem by creating a custom Equality Comparer:
public class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> list1, List<T> list2)
{
return list1.SequenceEquals(list2);
}
public int GetHashCode(List<T> list)
{
if(list != null && list.Length > 0)
{
var hashcode = list[0].GetHashCode();
for(var i = 1; i <= list.Length; i++)
hashcode ^= list[i].GetHashCode();
return hashcode;
}
return 0;
}
}
And then passing that to the Dictionary constructor:
Dictionary<List<String>, int> h =
new Dictionary<List<string>,int>(new ListEqualityComparer<String>());
The problem is the index by List, what you are indexing by isn't the data in the list but you are essentially indexing by the memory pointer to the List (i.e the memory address of where this List is located).
You Created one list at one memory location, you then created a totally different list at a different memory location (ie when you create a new instance). The two lists are different even though they contain the same data, and this means you can add as many as you want to the dictionary.
One solution is Rather than indexing by List would be to index by String and use a comma separated List containing all the data in your list as an index.
This won't ever work for you, because List<T>'s Equals and GetHashCode methods don't consider the contents of the list. If you want to use a collection of objects as a key, you'll need to implement your own collection type that overrides Equals in such a way as to check the equality of the objects in the collection (perhaps using Enumerable.SequenceEqual.)
The Dictionary class uses reference comparison to look for the specified key, that's why even if the lists contain the same items, they are different.
Perhaps I didn't explaine myself the first time around so here is my second go at it.
I need to declare objects from a list of strings inside an array.
So my array goes out to a DB and collects the names from one colums. This names will all be an object. Now I want to define each object with that name fromt he column dynamicly.
So the array has say 5 elements in it of type string.
So going though my for look i cannot seem t o dynamicly create the object.
So instead of manually going myobject test = new myobject();
I just want to declare it by looping though the array.
I'am not pretty sure what your question is, but if I see your code than you want to create objects in your array?
Maybe this is your solution:
MyObject[] myArray = new MyObject[4];
for (int i =0; i < myArray.Length; ++)
{
myArray[i] = new MyObject();
}
Hope this will help you.
MyObject[] myArray = new MyObject[3];
for (int i =0; i < myArray.Length; i++)
{
MyObject obj = new MyObject();
myArray[i] = obj;
}
You can convert an array to objects by using System.Linq's select operator. You create an object for every i in the array and return a new object for it like this
var array = new string[2]{"one","two"};
var objects = array.Select(i=> new Object{Name = array[i]}).ToArray();
I have the following method signature:
public void MyFunction(Object[,] obj)
I create this object:
List<List<Object>> obj = new List<List<Object>>;
Is there an easy way I can convert this to an Object[,]?
UPDATE:
The fact is I like to use Lists because I can easily add a new item. Is there a way I can declare my List<> object to fit this need? I know the number of columns in my Object[,] but not the number of rows.
No. In fact, these aren't necessarily compatible arrays.
[,] defines a multidimensional array. List<List<T>> would correspond more to a jagged array ( object[][] ).
The problem is that, with your original object, each List<object> contained in the list of lists can have a different number of objects. You would need to make a multidimensional array of the largest length of the internal list, and pad with null values or something along those lines to make it match.
You're not going to get a very simple solution for this (i.e. a few lines). LINQ/the Enumerable class isn't going to help you in this case (though it could if you wanted a jagged array, i.e. Object[][]). Plain nested iteration is probably the best solution in this case.
public static T[,] To2dArray(this List<List<T>> list)
{
if (list.Count == 0 || list[0].Count == 0)
throw new ArgumentException("The list must have non-zero dimensions.");
var result = new T[list.Count, list[0].Count];
for(int i = 0; i < list.Count; i++)
{
for(int j = 0; j < list[i].Count; j++)
{
if (list[i].Count != list[0].Count)
throw new InvalidOperationException("The list cannot contain elements (lists) of different sizes.");
result[i, j] = list[i][j];
}
}
return result;
}
I've included a bit of error handling in the function just because it might cause some confusing errors if you used it on a non-square nested list.
This method of course assumes that each List<T> contained as an element of the parent List is of the same length. (Otherwise you really need to be using a jagged array.)
Here is a solution using Linq's Aggregate extension.
Note that the below does not check, nor is concerned if it gets a jagged sub list, it uses the max size of all the sublists and fills in according to the current list. If that is a concern one could add a check to the if to check for the same count amongst all the sub lists.
public static T[,] To2DArray<T>(this List<List<T>> lst)
{
if ((lst == null) || (lst.Any (subList => subList.Any() == false)))
throw new ArgumentException("Input list is not properly formatted with valid data");
int index = 0;
int subindex;
return
lst.Aggregate(new T[lst.Count(), lst.Max (sub => sub.Count())],
(array, subList) =>
{
subindex = 0;
subList.ForEach(itm => array[index, subindex++] = itm);
++index;
return array;
} );
}
Test / Usage
var lst = new List<List<string>>() { new List<string>() { "Alpha", "Beta", "Gamma" },
new List<string>() { "One", "Two", "Three" },
new List<string>() { "A" }
};
var newArray = lst.To2DArray();
Result:
To be blunt, the answer is no, not easily.
Perhaps you would like to edit your question to give us more background about why these declarations are needed and we can help you with your root problem?
Re your update:
I assume you cannot change the function you need to pass this into.
I don't see why you cannot just use an object[,] to begin with. This is my recommendation.
I doubt this will help you in your situation, but it might make some of the array working easier on you to start with. Do you know about the .ToArray() method on a List?