0

I'm using dictionaries in C#, and I've spent a couple of hours figuring out why my program doesn't work, and the reason is that when I manipulate a copy of a dictionary I made, then these manipulations also affect the original dictionary for some reason.

I've boiled my problem down to the following example:

using System; using System.Collections.Generic; class Program { static void Main() { Dictionary<int, List<int>> D = new Dictionary<int, List<int>>(); List<int> L1 = new List<int>(){ 1, 2, 3 }; List<int> L2 = new List<int>() { 4, 5, 6 }; D.Add(1,L1); D.Add(2,L2); Dictionary<int, List<int>> Dcopy = new Dictionary<int, List<int>>(D); Dcopy[1].Add(4); } } 

In this code, when I add an element to the list corresponding to key 1 in the copy, this element also appears in the original dictionary.

When I search online, it seem to have something to do with "reference types", and the recommended fix always seem to involve a code similar to

Dictionary<int, List<int>> Dcopy = new Dictionary<int, List<int>>(D); 

which I did include in my program, but for some reason, this does not work.

Any suggestions as to why it doesn't work in my case, and any advice on what to do instead?

Best regards.

1

3 Answers 3

6

You're doing a shallow copy, instead of a deep copy. You basically need to iterate through your dictionary and create new lists

var Dcopy = new Dictionary<int, List<int>>(); foreach (var entry in D) { Dcopy.Add(entry.Key, new List<int>(entry.Value)); } 

Or you can use the following Linq instead of the foreach

var DCopy = D.ToDictionary(entry => entry.Key, entry => new List<int>(entry.Value)); 

Since your lists contains int which is a value type you do not need to "clone" deeper than the lists. If instead the list contained reference types then you'd have to additionally clone them as well and possibly any reference properties all the way down.

Sign up to request clarification or add additional context in comments.

3 Comments

Note, if the list was holding something that was mutable (a class with properties you could set) you would also need to make copies of each item in the list too (also making copies of any mutable properties, and properties of properties, and so on...).
Thanks. I understand how it behaves now, but am confused as to why it was build to behave this way. In unfortunate circumstances, where you have a complicated nesting of reference types (which I will read about to understand better) or of "mutable items", you would have to carefully copy each thing in the nesting and patch them together to get a structure that is genuinely distinct from the original?
@HowDoICSharply For a case like this you can write a fairly simple code to do the deep copy. If you are working with a more complicated nested structure then you'd probably want to check out the question that Alexie linked in the comments.
4

The dictionary copy constructor makes a shallow copy of the dictionary. Since the values are lists (reference types) the lists are not cloned. If you want to make a deep copy you need to clone the values as well:

 Dictionary<int, List<int>> Dcopy = D.ToDictionary(kvp => kpv.Key, kvp => kvp.Value.ToList()); 

Since the values are collection of value types then there's no need to close the contents of the list - cloning the list itself is sufficient. Same for the keys - they are value types so no cloning is necessary.

2 Comments

"If you want to make a deep copy you need to close the values as well" did you mean "you need to clone the values as well"? or do you really mean close as in "Variable closure"
@ScottChamberlain Thanks - I meant "clone". Fixed.
-1

If you don't need a deep copy of the lists, why not simply use .NET provided constructor, avoiding extension calls?

Dictionary<int, List<int>> Dcopy = new Dictionary<int,List<int>>(D); 

1 Comment

That's exactly what the OP is doing and obviously they do want a deep copy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.