狛ログ

2021年12月28日火曜日

C# List内の要素同士で一致するものがあるか確認方法。

オフィス狛 技術部のHammarです。

プログラム実装時に、配列やList同士で一致するものがあるかどうかチェックする、というような場合が多々あると思います。
今回はC#でこのチェックをさっときれいに書く方法がないか調べてみて、良さそうな書き方を見つけたので、ご参考程度にちょっと共有したいと思います。

まず単純に、2つのList内に同一のものがあるかどうかチェックするする場合、下記のようなFindAllメソッド等を使えば簡単に確認ができます。
string[] fruitsAry1 = new string[] { "Apple", "Banana", "Orange", "Grape" };
string[] fruitsAry2 = new string[] { "Apple", "Grape", "Grapefruit", "Strawberry" };
List<string> list1 = new List<string>(fruitsAry1);
List<string> list2 = new List<string>(fruitsAry2);
List<string> fruitsList = list1.FindAll(list2.Contains);
結果上記のfruitsListは{ "Apple", "Grape" }になります。

単純なList同士であれば上記のような方法でチェックできますが、例えばListに複数要素が含まれている場合で、ある要素だけ、一致するかどうかをチェックしたい場合は、ちょっと工夫が必要になります。

例えば

■Fruits.cs

namespace Fruits
{
	public class FruitsData
	{
	    public string id { get; set; }
	    public string name { get; set; }
	}
}

■CheckFruits.cs

List<FruitsData> fruitsList1 = new List<FruitsData>()
{
    new FruitsData {Id = "1", Name = "Apple" },
    new FruitsData {Id = "2", Name = "Banana" }
    new FruitsData {Id = "3", Name = "Orange" }
    new FruitsData {Id = "4", Name = "Grape" }
};

List<FruitsData> fruitsList2 = new List<FruitsData>()
{
    new FruitsData {Id = "1", Name = "Apple" },
    new FruitsData {Id = "2", Name = "Grape" }
    new FruitsData {Id = "3", Name = "Grapefruit" }
    new FruitsData {Id = "4", Name = "Strawberry" }
};
上記のような場合でNameが一致するものがあるか、チェックする場合、素直にやると以下のような感じでしょうか
bool isSame = false;
foreach(var fruits1 in fruitsList1)
{
    if(isSame)
    {
        break;
    }
    foreach (var fruits2 in fruitsList2)
    {
        if(fruits2.Name.Equals(fruits1.Name))
        {
            isSame = true;
            break;
        }
    }
}
2つのリストを回して一致するものがあったら抜けるという、すごい単純なものですが、一致するものがあるかどうかのチェックだけのためにこれを書くのはちょっと長いですよね。

もうちょっとだけ簡略化すると、Existsメソッドを使えばこのようにも書けると思います。
bool isSame = false;
foreach(var fruits1 in fruitsList1)
{
    if(fruitsList2.Exists(fruitsItem2 => fruitsItem2.Name.Equals(fruits1.Name)))
    {
        isSame = true;
        break;
    }
}
結構すっきりしましたが、fruitsList1をとりあえず回さないといけないので、ここまできたらループさせずにいけそうな気がします。
で、上記を踏まえて、さらにFindメソッドを使って、最終的にはこんな感じに簡略化できました。
var machedFruits = fruitsList1.Find(fruitsItem1 => 
    fruitsList2.Exists(fruitsItem2 => fruitsItem2.Name.Equals(fruitsItem1.Name))
);
FindメソッドとExistsメソッドを使ってループを使わずに一致する要素の確認ができました。
ちなみにこのFindメソッドの返り値は、全体の中で最もインデックス番号の小さい要素が返ってきます。
一致するものが無い場合はnullが返ってきますので、単純に一致するかどうかのチェックとしては、nullが返ってこなかったら一致しているということになります。

この他にも、Linqを使ったり等いろいろと方法があると思いますが(もっと簡略化もできそう)、方法の1つとしてご参考いただければと思います。

0 件のコメント:

コメントを投稿