2次元(多次元)配列の比較

2019年6月26日

次のコードは、data1,data2とdata3の2次元配列の内容比較をしようとしたものです。

配列どうしの内容比較

==で比較してみる

まず、data1とdata2の比較です。この場合、期待としては、trueですが、どうでしょう?

コード

string[,] data1 =
{
    { "ABC", "ABC", "ABC", },
    { "ABC", "ABC", "ABC", },
};

string[,] data2 =
{
    { "ABC", "ABC", "ABC", },
    { "ABC", "ABC", "ABC", },
};

bool isEqual;

if (data1 == data2)
{
    isEqual = true;
}
else
{
    isEqual = false;
}
Console.WriteLine($"data1 == data2   {isEqual}");

実行結果

期待した結果にはなりませんでした。

data1 == data2   False

原因

data1,data2はいずれも配列のため参照型になります。参照型とは、変数にデータが保存された場所(アドレス)が格納されている型です。data1とdata2はそれぞれ別のメモリ上に保存されているのでその場所が同じとはなりません。

(補足)コードのリファクタリング

修正する前に、コードが冗長なのですっきりさせましょう。

bool isEqual;

if (data1 == data2)
{
    isEqual = true;
}
else
{
    isEqual = false;
}
Console.WriteLine($"data1 == data2   {isEqual}");

if文は、data1とdata2の比較結果をisEqual変数に代入することで省略できます。

bool isEqual = (data1 == data2);

Console.WriteLine($"data1 == data2   {isEqual}");

さらに比較文(data1 == data2)を直接Writelineに入れてしまいます。

Console.WriteLine($"data1 == data2   {data1 == data2}");

すっきりしました。
では、改めて内容比較を考えてみます。

ループを使った処理

配列の内容を要素ごとに比較する

var sizeX = data1.GetLength(1);
var sizeY = data1.GetLength(0);

bool isEqual = true;

for (int y = 0; y < sizeY; y++)
{
    for (int x = 0; x < sizeX; x++)
    {
        if (data1[y, x] != data2[y, x])
        {
            isEqual = false;
        }
    }
}

Console.WriteLine($"data1 == data2   {isEqual}");

結果

data1 == data2   True

期待どおりの結果になりました。要素を一つずつ取り出して比較しています。1箇所でも違っていたら結果がfalseになるようにしています。考え方はシンプルですね。どのように処理されるのかよく考えてみましょう。

LINQを使った処理

先ほどと同じ処理をLINQを使って実現しています。
data1.Cast<string>()で、配列をstring[,]型からIEnumerableにキャストしています。これで、LINQが使えるようになります。SequenceEqual()メソッドで要素内容の比較が行えるので、問題なく動作します。

bool isEqual = data1.Cast<string>().SequenceEqual(data2.Cast<string>());
Console.WriteLine($"data1 == data2   {isEqual}");

多次元配列の行列の考え方

行は英語でLine(ライン)、列はColumn(カラム)といいます。
2次元座標と考えると、
new int[Y軸方向, X軸方向];
と考えるとわかりやすい?

2次元座標と考えると、
new int[Y軸方向, X軸方向];
と考えるとわかりやすい?

// 5行(縦の数)2列(横の数)の配列
int[,] a = new int[5,2]
{
    {1,2 },
    {1,2 },
    {1,2 },
    {1,2 },
    {1,2 },
};

// GetLength(0)は行数を取得
Console.WriteLine($"a.GetLength(0)  {a.GetLength(0)}");

// GetLength(1)は列数を取得
Console.WriteLine($"a.GetLength(1)  {a.GetLength(1)}");

// 結果
// a.GetLength(0)  5
// a.GetLength(1)  2

C#

Posted by hidepon