まず、浅いコピーでリストをコピーする方法について説明します。そして、浅いコピーで問題が発生する可能性がある状況と、深いコピーで解決する方法について説明します。
1. リストのコピー(浅いコピー)
浅いコピーでリストをコピーする方法を紹介します。
1.1 Listコンストラクタを使用した方法
以下の例のように new List<string>(list)
でリストを作成するときは、引数としてリストを渡してコピーできます。
using System;
namespace Example {
public class Program {
public static void Main(string[] args) {
List<string> list = new List<string>() {"a", "b", "c", "d"};
List<string> copy = new List<string>(list);
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));
}
}
}
Output:
a, b, c, d
a, b, c, d
1.2 List.ToList() を使った方法
list.ToList()
はコピーされたリストを返します。
List<string> list = new List<string>() {"a", "b", "c", "d"};
List<string> copy = list.ToList();
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));
Output:
a, b, c, d
a, b, c, d
1.3 List.GetRange() を使った方法
list.GetRange(index, count)
は、リストの index から count 個数だけの要素を新しいリストに追加して返します。
以下のように GetRange()
にリストをコピーできます。
List<string> list = new List<string>() {"a", "b", "c", "d"};
List<string> copy = list.GetRange(0, list.Count);
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));
Output:
a, b, c, d
a, b, c, d
2. 浅いコピーで発生する問題
string、intのような基本データ型ではなく、クラスオブジェクトを持っているリストのときに浅いコピーを使用したときに問題になることがあります。
たとえば、以下の例は
Person
オブジェクトのリストを浅いコピーにコピーします。- コピーされたリストで
Index 0
のPerson
オブジェクトのage
を 0 に変更します。 - 元のリストとコピーされたリストの内容を確認してみると、どちらも
John
のage
が 0 に変更されました。
たとえコピーはリストがオブジェクト情報だけをコピーして参照するため、オブジェクト内のデータはコピーされず、2つのリストが一緒に参照することになります。 このデータが変更されると、元のリストとコピーリストが参照するオブジェクト情報が一緒に変更されます。
using System;
namespace Example {
public class Person {
public string name;
public int age;
public Person(string name, int age) {
this.name = name;
this.age = age;
}
public override string ToString() {
return "[" + name + ", " + age + "]";
}
}
public class Program {
public static void Main(string[] args) {
List<Person> list = new List<Person>();
list.Add(new Person("John", 30));
list.Add(new Person("Patrick", 34));
list.Add(new Person("Doe", 22));
List<Person> copy = new List<Person>(list);
copy.ElementAt(0).age = 0;
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));
}
}
}
Output:
[John, 0], [Patrick, 34], [Doe, 22]
[John, 0], [Patrick, 34], [Doe, 22]
3. リストコピー(深コピー)
List.ConvertAll(converter)
はリストの要素を converter
を使って別のデータに変更する関数です。
リストのすべての要素に対して以下のように Person
オブジェクトを再生成して返すと、オブジェクト自体をコピーしたリストが生成されます。
ConvertAll(p => new Person(p.name, p.age))
オブジェクト自体をコピーしたため、元のリストとコピーされたリストは異なるオブジェクトを持っており、以下のように特定の要素の値を変更しても他のリストに影響を与えなくなります。
using System;
namespace Example {
public class Person {
public string name;
public int age;
public Person(string name, int age) {
this.name = name;
this.age = age;
}
public override string ToString() {
return "[" + name + ", " + age + "]";
}
}
public class Program {
public static void Main(string[] args) {
List<Person> list = new List<Person>();
list.Add(new Person("John", 30));
list.Add(new Person("Patrick", 34));
list.Add(new Person("Doe", 22));
List<Person> copy = list.ConvertAll(
p => new Person(p.name, p.age));
copy.ElementAt(0).age = 0;
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));
}
}
}
Output:
[John, 30], [Patrick, 34], [Doe, 22]
[John, 0], [Patrick, 34], [Doe, 22]
Related Posts
- C# - Dictionaryからkey、valueを取得する
- C# - Dictionary 巡回, foreach, for ループ
- C# - Dictionaryからkey、valueを削除する
- C# - Dictionary.add()でデータを追加する
- C# - Dictionary宣言と初期化
- C# - 文字列をDouble、Floatに変換
- C# - 文字列をリストに変換
- C# - 日付計算、DateTime時間プラス減算
- C# - 日付文字列をDateTimeに変換
- C# - 2つの日付/時刻比較、DateTime.Compare()
- C# - Sleep、数秒間遅らせる
- C# - TimestampをDateTimeオブジェクトに変換する
- C# - 現在時刻を取得する、DateTime
- C# - 文字列リストを文字列に変換
- C# - リストコピー(浅いコピー、深いコピー)
- C# - 2次元リスト宣言と初期化
- C# - リスト宣言と初期化
- C# - リストの長さ、サイズを取得する
- C# - リスト合計、平均計算
- C# - リスト要素を削除する(RemoveAt、RemoveAt、RemoveAll)
- C# - リストから空の文字列、nullを削除する