3

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?

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
kgsw
  • 95
  • 1
  • 10
  • Do you want to copy all the List instances as well? What about their contents? What are they Lists of? `List[,]`? – Blorgbeard Feb 25 '16 at 03:22
  • OK, with formatting, I can see it's ``. So, do you want `mycopy` to have copies of all the `MyClass` instances? – Blorgbeard Feb 25 '16 at 03:23
  • @Blorgbeard: No, it looks like your first assumption is correct: it's a 2D array of `List`. – Jim Mischel Feb 25 '16 at 03:29
  • I want an exact duplicate of the myarraylist, so I can change one but it does not affect the other. They are an array of of MyClass which contains strings and ints about 10 different variables. – kgsw Feb 25 '16 at 03:30
  • 1
    @JimMischel yes, I know. Without code formatting, the `` is stripped because it looks like html, so all I could see was "List[,] mycopy". – Blorgbeard Feb 25 '16 at 03:30
  • Easy way I can think of is just initializing a new var with the same matrix specs as `myArrayList` then just using two `for` statements to iterate over the `rectangular array` and copying the `List` from the same position in in the former list. If that makes sense. Don't want to post an answer until you've tried it. – Gabe Feb 25 '16 at 03:43
  • Basically what Jim just posted lol – Gabe Feb 25 '16 at 03:45

3 Answers3

3

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)?

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • Well explained answer - Commented pretty much the same thing in the OP - I just wanted to see if he'd try it first before posting. Nevertheless +1 for the in depth response. – Gabe Feb 25 '16 at 03:49
0

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();
smead
  • 1,768
  • 15
  • 23
0

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.