How to make a copy of a list?

I wish to make a copy of a list, where the elements of the list are also copied, instead of just the references, so I can then change them without affecting the original elements.

It seems a very simple thing, it should be like:

MySecondList = MyFirstList.CopyAll();

but I cannot find it. Come to think of it, I don't know how to copy the elements one by one either if they aren't simple types. Strange, I never needed to do this before.

Help is appreciated,

Guido



Answer this question

How to make a copy of a list?

  • RajuK

    No, that doesn't help me because the elements are still references to the same instances as in the old list.

    Further, this roundabout way is far more cumbersome than using a constructor.


  • Duck4565654

    But if they were still references to the same instances as in the old list wouldn't the output be:

    Output:

    origional: -1 modified: -1
    origional: 0 modified: 0
    origional: 1 modified: 1
    origional: 2 modified: 2
    origional: 3 modified: 3
    origional: 4 modified: 4
    origional: 5 modified: 5
    origional: 6 modified: 6
    origional: 7 modified: 7
    origional: 8 modified: 8

    But it is not!  We updated the items in the copied list and not the items in the origional therefore the items in copied list are pointing to a different location than that of the origional list.

    I'm not sure about the objects within each item of the list, but each of those items are pointing to a new location in memory than the items in the origional list.



  • Andres Aguiar

    Guido,

        I believe the prefered way to copy any array is using the Array.Copy(...) method. When dealing with an array you can use the List<>'s ToArray() method to make a copy of your list.

    public static List<int> Copy(List<int> origList)
    {
        int[] newIntArray = new int[origList.Count];
        Array.Copy(
            origList.ToArray(),
            newIntArray,
            origList.Count);

        return new List<int>(newIntArray);
    }

    Example:

    static void Main(string[] args)
    {
        List<int> integerList = new List<int>();
        for (int i = 0; i < 10; i++)
        {
            integerList.Add(i);
        }
        List<int> newIntegerList = Copy(integerList);
        for (int i = 0; i < integerList.Count; i++)
        {
            newIntegerListIdea = i - 1;
            Console.WriteLine("origional: {0} modified: {1}",
                integerListIdea,
                newIntegerListIdea);
        }
    }

    Output:

    origional: 0 modified: -1
    origional: 1 modified: 0
    origional: 2 modified: 1
    origional: 3 modified: 2
    origional: 4 modified: 3
    origional: 5 modified: 4
    origional: 6 modified: 5
    origional: 7 modified: 6
    origional: 8 modified: 7
    origional: 9 modified: 8

    Hope this helps!



  • tpiazza55

    OK, I am using a constructor now for both the element class and the list class:

    public MyList(MyList myToCopyList)

    { foreach (MyElement myToCopyElement in myToCopyList) Add(new MyElement(myToCopyElement)); }

    This works and looks relatively neat, but of course the extra constructor for MyElement is quite ugly.


  • janderson

    Well, the syntax should take care of that.

    For instance:

    myNewList=myOldList.Copy();

    copies the elements as references,

    myNewList=myOldList.Copy(myElement);

    deep-copies the myElements but not any class instances within them, and

    myNewList=myOldList.Copy(myElement.Copy(mySecondClassInstance, myFifthClassInstance))

    also deep-copies my second and fifth class instances inside the elements, etc.

    Or something like this, and where the Copy method can be overridden when needed.


  • m.mirzakhah

    I don't think I understand what your suggesting with that code sample. How does the argument tell the list when to make a new copy of an object and when just to copy the reference

    In any case, what I was suggesting was to write a function like this:

    [code]

    public List<T> CopyList<T>(List<T> list) where T : ICloneable {

    List<T> result = new List<T>(list.Count);

    foreach(T element in list) {

    result.Add((T)element.Clone());

    }

    return result;

    }

    [/code]

    While the ICloneable interface does have certain difficiencies, this implementation has the advantage that it can copy any list where its element type implements the ICloneable interface. So, it can be reused for lists of various types, as long as the list's element type implements the ICloneable.Clone method.


  • Julio Parra

    Nimrad is correct. There is no built-in "automagic" deep copy routine provided by the Framework. There are a few problems with deep copies, which must be dealt with by the programmer and cannot be handled generally by the Framework.
    1. Scaling behaviour: Shallow copies scale as O(n) - e.g. linearly - where n is the number of elements in an array or fields in a class/struct. The scaling behaviour of deep copies depends on the structure of your classes/structs.
    2. Reference cycles: Let's say A references B and C. B also references C. If you deep copy A, do you want two copies of C or one Chances are only one, but that's for your deep copy algorithm to decide.
    3. Deep or shallow on dependent objects: Although you might want to deep copy the collection, objects referenced by object in the collection might better be shallow copied. For instance, let's say you have a collection of orders, which reference a customer. Although you want to take a copy of the orders, the referenced customer objects might need to reference the same customer object as the original.
    So the semantics of a deep copy are highly application and/or class/struct dependent.

    A good (and short) discussion of ICloneable can be found here:
    http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=373454&SiteID=1

    Basically there are a few design problems with ICloneable, notably the fact that it doesn't specify whether a deep or shallow copy is performed and that it is type-unsafe. (Clone returns an object, which must then be cast to a specific type.) The preferred implementation technique is using copy constructors - a constructor that takes a reference to an object of the same type.

    Hopefully this helps rationalize why deep copy isn't built into the Framework.


  • Cush

    We are not talking about integers.
  • bvautier

    Unfortunately, there is no automated way to do this, as far as I know. I assume that your list contains objects of classes that you created. If this is the case, then probably the best answer is to have them implement the ICloneable interface so that you can use the Clone method to make the copies for your second list. When implementing the Clone method, it may be usefull to use the MemberwiseClone method, but be warned that this makes only a shallow copy.

    I hope this points you in the right direction. If you have any more questions, please ask.


  • SJVCT

    Shallow means that it only copies the references, right

    I don't see how that solves anything then, as I would still have to copy every single bit of my elements explicitly (so I might as well write a copy method for them instead of using an interface).

     


  • How to make a copy of a list?