最近はC#に凝っています。LINQとvar
が最高すぎて、Javaにはもどれない(´・ω・`)
リストや配列を生成する際、すべての要素を特定の値で初期化したいという場合、プログラミング言語の種類によっては専用のコンストラクタが用意されているものもありますが、C#ではEnumerable#Repaeat
を利用する方法がよさそうです。
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var list = Enumerable.Repeat("a", 20).ToList();
var str = "[" + string.Join(",", list) + "]";
Console.WriteLine(str);
// => [a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a]
}
}
注意すべきは第1引数の値が要素ごとに複製されないということです。int
やstring
のようなimmutableなクラスでは問題ありませんが、この方法によりmutableなオブジェクトで配列やリストを初期化したいという場合には気を付ける必要があります。以下のサンプルコードでは、mutableなクラスのうち、もっとも代表的なもののひとつSystem.Collections.Generic.List
を例として、この方法が想定通り動作しないことを示しています。
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var matrix = Enumerable.Repeat(new List<string>() { "a", "a" }, 2).ToList();
matrix[0][0] = "b";
var str = matrix.Aggregate("", (sum, row) => sum + "[" + string.Join(",", row) + "]");
Console.WriteLine(str);
// 想定していた値: [b,a][a,a]
// 実際の値: [b,a][b,a]
// ===> new List<string>() { "a", "a" }が複製されていないことが確認できます。
}
}
ちなみにこのサンプルコードを想定通りに機能させる場合は、以下のような初期化方法、つまりRepeat
ではなくRange
とSelect
を組み合わせる方法を採用すべきです。
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var matrix = Enumerable.Range(0, 2).Select((x) => new List<string>() { "a", "a" }).ToList();
matrix[0][0] = "b";
var str = matrix.Aggregate("", (sum, row) => sum + "[" + string.Join(",", row) + "]");
Console.WriteLine(str);
// 想定していた値 => [b,a][a,a]
// 実際の値 => [b,a][a,a]
}
}