じゃがいも畑

開発ネタの記録

C# 2次元リストのコピー

C# でリストAの中身をリストBにコピーしてリストBで値の変更などをしたい場合、以下のようにすれば値渡しでコピーができる

        var listA = new List<int> { 1, 2, 3 };
        var listB = new List<int>(listA);  // 値渡し

        // listB = listAは参照渡し

        listB[0] = 3;
        listB[1] = 3;
        listB[2] = 3;

        Console.WriteLine(string.Join(" ", listA));     // 1 2 3
        Console.WriteLine(string.Join(" ", listB));     // 3 3 3

けど2次元リストで同じ方法を使うと入れ子になったリストが参照渡しになってしまう

        var listA = new List<List<int>> {
            new List<int>{1, 2, 3},
            new List<int>{1, 2, 3},
        };

        // 外のリストは値渡し、入れ子のリストは参照渡し
        var listB = new List<List<int>>(listA);     

        listB[1][0] = 3;
        listB[1][1] = 3;
        listB[1][2] = 3;

        foreach (var item in listA) Console.WriteLine(string.Join(" ", item));  
        foreach (var item in listB) Console.WriteLine(string.Join(" ", item));  

       // 出力結果
       // 1 2 3 3 3 3
       // 1 2 3 3 3 3

listAは1 2 3 1 2 3のままでいてほしいのに1 2 3 3 3 3になってしまっている

しょうがないので2次元リストをDeepCopyする拡張メソッドを作る

namespace Extension
{
    public static class Extensions
    {
        public static List<List<T>> DeepCopy<T>(this List<List<T>> source)
        {
            var copyList = new List<List<T>>();
            foreach (var item in source)
            {
                copyList.Add(new List<T>(item));
            }
            return copyList;
        }
    }
}

これでOK

        var listA = new List<List<int>> {
            new List<int>{1, 2, 3},
            new List<int>{1, 2, 3},
        };

        var listB = listA.DeepCopy();

        listB[1][0] = 3;
        listB[1][1] = 3;
        listB[1][2] = 3;

        foreach (var item in listA) Console.WriteLine(string.Join(" ", item));
        foreach (var item in listB) Console.WriteLine(string.Join(" ", item));

       // 出力結果
       // 1 2 3 1 2 3
       // 1 2 3 3 3 3