迭代中的字典 AddRange 将范围添加到当前和上一个指针

Dictionary AddRange in iteration adds range to both current and previous pointer

我正在根据提供的 Project-2-Groups 和 Group-2-Categories 词典创建 Project-2-Categories 词典。
在我的代码示例中,我期望得到以下结果:

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

然而,实际结果是:

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

如果能帮我澄清我在这里的误解,我将不胜感激。
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());
    }
}

列表是引用类型。当您第一次分配列表时,您会为 P1 和 P2 分配相同的列表。在此之后将范围添加到 P2 时,实际上是将其添加到现有列表中。这就是为什么你有相同的结果。因此,您已将列表的副本分配给 P1 和 P2,这样您将拥有 2 个独立的列表。在此之后,您可以将范围添加到独立列表 P2.

并且我更改了你的算法以使代码更清晰

    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);
            }

您可以重复使用相同的列表实例。

但是,每次,您都必须通过 Clear() 清空它,然后再用 out 参数在行中再次填充它,而不是创建新的 List<string> 实例。