Home > Software design >  Dictionary AddRange in iteration adds range to both current and previous pointer
Dictionary AddRange in iteration adds range to both current and previous pointer

Time:02-04

I am creating a Project-2-Categories dictionary from supplied Project-2-Groups and Group-2-Categories dictionaries.
In my code example I expected the following result:

{
 "P1": [ "1", "11", "111" ],
 "P2": [ "1", "11", "111", "2", "22", "222" ],
}

However, the actual result is:

{
 "P1": [ "1", "11", "111", "2", "22", "222" ],
 "P2": [ "1", "11", "111", "2", "22", "222" ],
}

I would appreciate any help clearing up what I am misunderstanding here.
Link to fiddle

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        var proj2categories = new Dictionary<string, List<string>>();
        
        var proj2groups = new Dictionary<string, List<string>>
        {
            { "P1", new List<string>{ "Grp1" } },
            { "P2", new List<string>{ "Grp1", "Grp2" } },
        };
        var group2categories = new Dictionary<string, List<string>>
        {
            { "Grp1", new List<string>{ "1", "11", "111" } },
            { "Grp2", new List<string>{ "2", "22", "222" } },
        };
        
        foreach (var p2g in proj2groups)
        {
            var projKey = p2g.Key;
            foreach (var agroup in p2g.Value)
            {
                if (!group2categories.TryGetValue(agroup, out var categories))
                    continue;

                if (proj2categories.ContainsKey(projKey))
                    proj2categories[projKey].AddRange(categories);
                else
                    proj2categories.Add(projKey, categories);
            }
        }
        
        Console.WriteLine("Expected: 3.   Actual: "   proj2categories["P1"].Count()   "    FAILED");
        Console.WriteLine("Expected: 1.   Actual: "   proj2categories["P1"].First());
        Console.WriteLine("Expected: 111. Actual: "   proj2categories["P1"].Last()   "  FAILED");
        Console.WriteLine("Expected: 6.   Actual: "   proj2categories["P2"].Count());
        Console.WriteLine("Expected: 1.   Actual: "   proj2categories["P2"].First());
        Console.WriteLine("Expected: 222. Actual: "   proj2categories["P2"].Last());
    }
}

CodePudding user response:

List is a reference type. When you assigned list for the first time , you are assigned the same list for both P1 and P2. When after this you add range to P2, as a matter of fact you add it to an existing list. This is why you have the same result. So you have assign a copy of the list to P1 and P2, this way you will have 2 independent lists. After this you can add range to independent list P2.

And I changed your algorithm to make the code more clear

    foreach (var g2c in group2categories)
        foreach (var p2g in proj2groups)
            if (p2g.Value.Contains(g2c.Key))
            {
                var key = p2g.Key;
                var val = g2c.Value;

                if (!proj2categories.TryGetValue(key, out _))
                    proj2categories[key] = val.ToList();
                else
                    proj2categories[key].AddRange(val);
            }
  •  Tags:  
  • Related